From 54839f14166c9ecefa37c7417da8505836041ac1 Mon Sep 17 00:00:00 2001 From: Achyut Jhunjhunwala Date: Mon, 17 Jun 2024 19:11:51 +0200 Subject: [PATCH 001/123] =?UTF-8?q?Add=20support=20to=20run=20synthtrace?= =?UTF-8?q?=20for=20locally=20running=20kibana=20serverless=20a=E2=80=A6?= =?UTF-8?q?=20(#186308)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds support for running synthtrace on locally running serverless kibana and es --- packages/kbn-apm-synthtrace/src/cli/utils/get_service_urls.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kbn-apm-synthtrace/src/cli/utils/get_service_urls.ts b/packages/kbn-apm-synthtrace/src/cli/utils/get_service_urls.ts index 3f13cae5e039c3..3967040a569af9 100644 --- a/packages/kbn-apm-synthtrace/src/cli/utils/get_service_urls.ts +++ b/packages/kbn-apm-synthtrace/src/cli/utils/get_service_urls.ts @@ -12,7 +12,7 @@ import { Logger } from '../../lib/utils/create_logger'; import { RunOptions } from './parse_run_cli_flags'; async function discoverAuth(parsedTarget: Url) { - const possibleCredentials = [`admin:changeme`, `elastic:changeme`]; + const possibleCredentials = [`admin:changeme`, `elastic:changeme`, `elastic_serverless:changeme`]; for (const auth of possibleCredentials) { const url = format({ ...parsedTarget, From a9f5375fa89a275df6eeb625a25e7ba30bd7bbe4 Mon Sep 17 00:00:00 2001 From: rohanxz <115164234+rohanxz@users.noreply.github.com> Date: Mon, 17 Jun 2024 23:05:48 +0530 Subject: [PATCH 002/123] Gemini Connector Assistant Integration (#184741) --- .../impl/assistant/api/index.test.tsx | 12 +- .../impl/assistant/api/index.tsx | 8 +- .../use_load_connectors/index.tsx | 5 +- x-pack/packages/kbn-langchain/server/index.ts | 2 + .../server/language_models/constants.ts | 5 + .../language_models/simple_chat_model.test.ts | 9 +- .../language_models/simple_chat_model.ts | 13 +- .../kbn-langchain/server/utils/bedrock.ts | 9 +- .../kbn-langchain/server/utils/gemini.test.ts | 89 +++++ .../kbn-langchain/server/utils/gemini.ts | 80 +++++ .../kbn-langchain/server/utils/types.ts | 38 ++ .../connector_types.test.ts.snap | 338 +++++++++++++++++- .../server/lib/gen_ai_token_tracking.test.ts | 34 +- .../server/lib/gen_ai_token_tracking.ts | 37 +- ...get_token_count_from_invoke_stream.test.ts | 44 ++- .../lib/get_token_count_from_invoke_stream.ts | 64 ++++ .../server/lib/parse_stream.test.ts | 40 +++ .../server/lib/parse_stream.ts | 31 +- .../elastic_assistant/server/routes/utils.ts | 1 + .../stream/stream_observable.test.ts | 141 ++++++++ .../get_comments/stream/stream_observable.ts | 95 ++++- .../common/gemini/constants.ts | 2 + .../stack_connectors/common/gemini/schema.ts | 24 ++ .../stack_connectors/common/gemini/types.ts | 6 + .../public/connector_types/gemini/logo.tsx | 22 +- .../connector_types/gemini/gemini.test.ts | 299 +++++++++++++--- .../server/connector_types/gemini/gemini.ts | 160 ++++++++- 27 files changed, 1500 insertions(+), 108 deletions(-) create mode 100644 x-pack/packages/kbn-langchain/server/utils/gemini.test.ts create mode 100644 x-pack/packages/kbn-langchain/server/utils/gemini.ts create mode 100644 x-pack/packages/kbn-langchain/server/utils/types.ts diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx index c1c6f8e6a67aaa..0182c4061866b0 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx @@ -134,7 +134,7 @@ describe('API tests', () => { ); }); - it('calls the non-stream API when assistantStreamingEnabled is true and actionTypeId is gemini and isEnabledKnowledgeBase is true', async () => { + it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is gemini and isEnabledKnowledgeBase is true', async () => { const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, apiConfig: apiConfig.gemini, @@ -145,13 +145,13 @@ describe('API tests', () => { expect(mockHttp.fetch).toHaveBeenCalledWith( '/internal/elastic_assistant/actions/connector/foo/_execute', { - ...staticDefaults, - body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}', + ...streamingDefaults, + body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}', } ); }); - it('calls the non-stream API when assistantStreamingEnabled is true and actionTypeId is gemini and isEnabledKnowledgeBase is false and isEnabledRAGAlerts is true', async () => { + it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is gemini and isEnabledKnowledgeBase is false and isEnabledRAGAlerts is true', async () => { const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, apiConfig: apiConfig.gemini, @@ -164,8 +164,8 @@ describe('API tests', () => { expect(mockHttp.fetch).toHaveBeenCalledWith( '/internal/elastic_assistant/actions/connector/foo/_execute', { - ...staticDefaults, - body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":true}', + ...streamingDefaults, + body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":true}', } ); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx index fa12841a96152a..a554324515ad62 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx @@ -64,13 +64,7 @@ export const fetchConnectorExecuteAction = async ({ traceOptions, }: FetchConnectorExecuteAction): Promise => { // TODO add streaming support for gemini with langchain on - const isStream = - assistantStreamingEnabled && - (apiConfig.actionTypeId === '.gen-ai' || - apiConfig.actionTypeId === '.bedrock' || - // TODO add streaming support for gemini with langchain on - // tracked here: https://github.com/elastic/security-team/issues/7363 - (apiConfig.actionTypeId === '.gemini' && !isEnabledRAGAlerts && !isEnabledKnowledgeBase)); + const isStream = assistantStreamingEnabled; const optionalRequestParams = getOptionalRequestParams({ isEnabledRAGAlerts, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_connectors/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_connectors/index.tsx index b93c166a9c5d77..293993e82fde63 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_connectors/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_connectors/index.tsx @@ -30,6 +30,7 @@ export interface Props { const actionTypeKey = { bedrock: '.bedrock', openai: '.gen-ai', + gemini: '.gemini', }; export const useLoadConnectors = ({ @@ -44,7 +45,9 @@ export const useLoadConnectors = ({ (acc: AIConnector[], connector) => [ ...acc, ...(!connector.isMissingSecrets && - [actionTypeKey.bedrock, actionTypeKey.openai].includes(connector.actionTypeId) + [actionTypeKey.bedrock, actionTypeKey.openai, actionTypeKey.gemini].includes( + connector.actionTypeId + ) ? [ { ...connector, diff --git a/x-pack/packages/kbn-langchain/server/index.ts b/x-pack/packages/kbn-langchain/server/index.ts index 12c32c86563a80..1d521599518097 100644 --- a/x-pack/packages/kbn-langchain/server/index.ts +++ b/x-pack/packages/kbn-langchain/server/index.ts @@ -9,10 +9,12 @@ import { ActionsClientChatOpenAI } from './language_models/chat_openai'; import { ActionsClientLlm } from './language_models/llm'; import { ActionsClientSimpleChatModel } from './language_models/simple_chat_model'; import { parseBedrockStream } from './utils/bedrock'; +import { parseGeminiResponse } from './utils/gemini'; import { getDefaultArguments } from './language_models/constants'; export { parseBedrockStream, + parseGeminiResponse, getDefaultArguments, ActionsClientChatOpenAI, ActionsClientLlm, diff --git a/x-pack/packages/kbn-langchain/server/language_models/constants.ts b/x-pack/packages/kbn-langchain/server/language_models/constants.ts index d4d38d172f9750..be9866023120e4 100644 --- a/x-pack/packages/kbn-langchain/server/language_models/constants.ts +++ b/x-pack/packages/kbn-langchain/server/language_models/constants.ts @@ -11,6 +11,10 @@ export const getDefaultArguments = (llmType?: string, temperature?: number, stop temperature: temperature ?? DEFAULT_BEDROCK_TEMPERATURE, stopSequences: stop ?? DEFAULT_BEDROCK_STOP_SEQUENCES, } + : llmType === 'gemini' + ? { + temperature: temperature ?? DEFAULT_GEMINI_TEMPERATURE, + } : { n: 1, stop: stop ?? null, temperature: temperature ?? DEFAULT_OPEN_AI_TEMPERATURE }; export const DEFAULT_OPEN_AI_TEMPERATURE = 0.2; @@ -19,4 +23,5 @@ export const DEFAULT_OPEN_AI_TEMPERATURE = 0.2; export const DEFAULT_OPEN_AI_MODEL = 'gpt-4'; const DEFAULT_BEDROCK_TEMPERATURE = 0; const DEFAULT_BEDROCK_STOP_SEQUENCES = ['\n\nHuman:', '\nObservation:']; +const DEFAULT_GEMINI_TEMPERATURE = 0; export const DEFAULT_TIMEOUT = 180000; diff --git a/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.test.ts b/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.test.ts index 6a11466f9faa09..a9d2142fc39634 100644 --- a/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.test.ts +++ b/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.test.ts @@ -14,6 +14,7 @@ import { mockActionResponse } from './mocks'; import { BaseMessage } from '@langchain/core/messages'; import { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager'; import { parseBedrockStream } from '../utils/bedrock'; +import { parseGeminiStream } from '../utils/gemini'; const connectorId = 'mock-connector-id'; @@ -94,6 +95,7 @@ const defaultArgs = { streaming: false, }; jest.mock('../utils/bedrock'); +jest.mock('../utils/gemini'); describe('ActionsClientSimpleChatModel', () => { beforeEach(() => { @@ -216,6 +218,7 @@ describe('ActionsClientSimpleChatModel', () => { describe('_call streaming: true', () => { beforeEach(() => { (parseBedrockStream as jest.Mock).mockResolvedValue(mockActionResponse.message); + (parseGeminiStream as jest.Mock).mockResolvedValue(mockActionResponse.message); }); it('returns the expected content when _call is invoked with streaming and llmType is Bedrock', async () => { const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel({ @@ -238,7 +241,7 @@ describe('ActionsClientSimpleChatModel', () => { it('returns the expected content when _call is invoked with streaming and llmType is Gemini', async () => { const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel({ ...defaultArgs, - actions: mockActions, + actions: mockStreamActions, llmType: 'gemini', streaming: true, }); @@ -248,8 +251,8 @@ describe('ActionsClientSimpleChatModel', () => { callOptions, callRunManager ); - const subAction = mockExecute.mock.calls[0][0].params.subAction; - expect(subAction).toEqual('invokeAI'); + const subAction = mockStreamExecute.mock.calls[0][0].params.subAction; + expect(subAction).toEqual('invokeStream'); expect(result).toEqual(mockActionResponse.message); }); diff --git a/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.ts b/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.ts index 9f6f3a331a7fb1..161e3601ee3ae0 100644 --- a/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.ts +++ b/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.ts @@ -17,6 +17,7 @@ import { KibanaRequest } from '@kbn/core-http-server'; import { v4 as uuidv4 } from 'uuid'; import { get } from 'lodash/fp'; import { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager'; +import { parseGeminiStream } from '../utils/gemini'; import { parseBedrockStream } from '../utils/bedrock'; import { getDefaultArguments } from './constants'; @@ -75,8 +76,7 @@ export class ActionsClientSimpleChatModel extends SimpleChatModel { this.llmType = llmType ?? 'ActionsClientSimpleChatModel'; this.model = model; this.temperature = temperature; - // only enable streaming for bedrock - this.streaming = streaming && llmType === 'bedrock'; + this.streaming = streaming; } _llmType() { @@ -154,7 +154,6 @@ export class ActionsClientSimpleChatModel extends SimpleChatModel { return content; // per the contact of _call, return a string } - // Bedrock streaming const readable = get('data', actionResult) as Readable; if (typeof readable?.read !== 'function') { @@ -182,13 +181,9 @@ export class ActionsClientSimpleChatModel extends SimpleChatModel { } } }; + const streamParser = this.llmType === 'bedrock' ? parseBedrockStream : parseGeminiStream; - const parsed = await parseBedrockStream( - readable, - this.#logger, - this.#signal, - handleLLMNewToken - ); + const parsed = await streamParser(readable, this.#logger, this.#signal, handleLLMNewToken); return parsed; // per the contact of _call, return a string } diff --git a/x-pack/packages/kbn-langchain/server/utils/bedrock.ts b/x-pack/packages/kbn-langchain/server/utils/bedrock.ts index 4b0b6ca245ff24..08e884ef01da24 100644 --- a/x-pack/packages/kbn-langchain/server/utils/bedrock.ts +++ b/x-pack/packages/kbn-langchain/server/utils/bedrock.ts @@ -6,17 +6,10 @@ */ import { finished } from 'stream/promises'; -import { Readable } from 'stream'; import { Logger } from '@kbn/core/server'; import { EventStreamCodec } from '@smithy/eventstream-codec'; import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; - -type StreamParser = ( - responseStream: Readable, - logger: Logger, - abortSignal?: AbortSignal, - tokenHandler?: (token: string) => void -) => Promise; +import { StreamParser } from './types'; export const parseBedrockStream: StreamParser = async ( responseStream, diff --git a/x-pack/packages/kbn-langchain/server/utils/gemini.test.ts b/x-pack/packages/kbn-langchain/server/utils/gemini.test.ts new file mode 100644 index 00000000000000..3fcdb87b24551c --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/utils/gemini.test.ts @@ -0,0 +1,89 @@ +/* + * 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 { Readable } from 'stream'; +import { parseGeminiStream, parseGeminiResponse } from './gemini'; +import { loggerMock } from '@kbn/logging-mocks'; + +describe('parseGeminiStream', () => { + const mockLogger = loggerMock.create(); + let mockStream: Readable; + + beforeEach(() => { + jest.clearAllMocks(); + mockStream = new Readable({ + read() {}, + }); + }); + + it('should parse the stream correctly', async () => { + const data = + 'data: {"candidates":[{"content":{"role":"system","parts":[{"text":"Hello"}]},"finishReason":"stop","safetyRatings":[{"category":"safe","probability":"low"}]}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}\n'; + mockStream.push(data); + mockStream.push(null); + + const result = await parseGeminiStream(mockStream, mockLogger); + expect(result).toBe('Hello'); + }); + + it('should handle abort signal correctly', async () => { + const abortSignal = new AbortController().signal; + setTimeout(() => { + abortSignal.dispatchEvent(new Event('abort')); + }, 100); + + const result = parseGeminiStream(mockStream, mockLogger, abortSignal); + + await expect(result).resolves.toBe(''); + expect(mockLogger.info).toHaveBeenCalledWith('Bedrock stream parsing was aborted.'); + }); + + it('should call tokenHandler with correct tokens', async () => { + const data = + 'data: {"candidates":[{"content":{"role":"system","parts":[{"text":"Hello world"}]},"finishReason":"stop","safetyRatings":[{"category":"safe","probability":"low"}]}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}\n'; + mockStream.push(data); + mockStream.push(null); + + const tokenHandler = jest.fn(); + await parseGeminiStream(mockStream, mockLogger, undefined, tokenHandler); + + expect(tokenHandler).toHaveBeenCalledWith('Hello '); + expect(tokenHandler).toHaveBeenCalledWith('world '); + }); + + it('should handle stream error correctly', async () => { + const error = new Error('Stream error'); + const resultPromise = parseGeminiStream(mockStream, mockLogger); + + mockStream.emit('error', error); + + await expect(resultPromise).rejects.toThrow('Stream error'); + }); +}); + +describe('parseGeminiResponse', () => { + it('should parse response correctly', () => { + const response = + 'data: {"candidates":[{"content":{"role":"system","parts":[{"text":"Hello"}]},"finishReason":"stop","safetyRatings":[{"category":"safe","probability":"low"}]}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}\n'; + const result = parseGeminiResponse(response); + expect(result).toBe('Hello'); + }); + + it('should ignore lines that do not start with data: ', () => { + const response = + 'invalid line\ndata: {"candidates":[{"content":{"role":"system","parts":[{"text":"Hello"}]},"finishReason":"stop","safetyRatings":[{"category":"safe","probability":"low"}]}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}\n'; + const result = parseGeminiResponse(response); + expect(result).toBe('Hello'); + }); + + it('should ignore lines that end with [DONE]', () => { + const response = + 'data: {"candidates":[{"content":{"role":"system","parts":[{"text":"Hello"}]},"finishReason":"stop","safetyRatings":[{"category":"safe","probability":"low"}]}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":10,"totalTokenCount":20}}\ndata: [DONE]'; + const result = parseGeminiResponse(response); + expect(result).toBe('Hello'); + }); +}); diff --git a/x-pack/packages/kbn-langchain/server/utils/gemini.ts b/x-pack/packages/kbn-langchain/server/utils/gemini.ts new file mode 100644 index 00000000000000..68fa4c0363e138 --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/utils/gemini.ts @@ -0,0 +1,80 @@ +/* + * 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 { StreamParser } from './types'; + +export const parseGeminiStream: StreamParser = async ( + stream, + logger, + abortSignal, + tokenHandler +) => { + let responseBody = ''; + stream.on('data', (chunk) => { + const decoded = chunk.toString(); + const parsed = parseGeminiResponse(decoded); + if (tokenHandler) { + const splitByQuotes = parsed.split(`"`); + splitByQuotes.forEach((chunkk, index) => { + // add quote back on except for last chunk + const splitBySpace = `${chunkk}${index === splitByQuotes.length - 1 ? '' : '"'}`.split(` `); + + for (const char of splitBySpace) { + tokenHandler(`${char} `); + } + }); + } + responseBody += parsed; + }); + return new Promise((resolve, reject) => { + stream.on('end', () => { + resolve(responseBody); + }); + stream.on('error', (err) => { + reject(err); + }); + if (abortSignal) { + abortSignal.addEventListener('abort', () => { + logger.info('Bedrock stream parsing was aborted.'); + stream.destroy(); + resolve(responseBody); + }); + } + }); +}; + +/** Parse Gemini stream response body */ +export const parseGeminiResponse = (responseBody: string) => { + return responseBody + .split('\n') + .filter((line) => line.startsWith('data: ') && !line.endsWith('[DONE]')) + .map((line) => JSON.parse(line.replace('data: ', ''))) + .filter( + ( + line + ): line is { + candidates: Array<{ + content: { role: string; parts: Array<{ text: string }> }; + finishReason: string; + safetyRatings: Array<{ category: string; probability: string }>; + }>; + usageMetadata: { + promptTokenCount: number; + candidatesTokenCount: number; + totalTokenCount: number; + }; + } => 'candidates' in line + ) + .reduce((prev, line) => { + if (line.candidates[0] && line.candidates[0].content) { + const parts = line.candidates[0].content.parts; + const text = parts.map((part) => part.text).join(''); + return prev + text; + } + return prev; + }, ''); +}; diff --git a/x-pack/packages/kbn-langchain/server/utils/types.ts b/x-pack/packages/kbn-langchain/server/utils/types.ts new file mode 100644 index 00000000000000..d88adb4045e87d --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/utils/types.ts @@ -0,0 +1,38 @@ +/* + * 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 { Readable } from 'stream'; +import { Logger } from '@kbn/logging'; + +export type StreamParser = ( + responseStream: Readable, + logger: Logger, + abortSignal?: AbortSignal, + tokenHandler?: (token: string) => void +) => Promise; + +export interface GeminiResponseSchema { + candidates: Candidate[]; + usageMetadata: { + promptTokenCount: number; + candidatesTokenCount: number; + totalTokenCount: number; + }; +} +interface Part { + text: string; +} + +interface Candidate { + content: Content; + finishReason: string; +} + +interface Content { + role: string; + parts: Part[]; +} diff --git a/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap b/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap index f431271ad42f92..84f1c1966747b7 100644 --- a/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap +++ b/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap @@ -3037,6 +3037,49 @@ Object { ], "type": "any", }, + "stopSequences": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "items": Array [ + Object { + "flags": Object { + "error": [Function], + "presence": "optional", + }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "array", + }, + "temperature": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "number", + }, "timeout": Object { "flags": Object { "default": [Function], @@ -3155,6 +3198,49 @@ Object { ], "type": "any", }, + "stopSequences": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "items": Array [ + Object { + "flags": Object { + "error": [Function], + "presence": "optional", + }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "array", + }, + "temperature": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "number", + }, "timeout": Object { "flags": Object { "default": [Function], @@ -3179,6 +3265,254 @@ Object { `; exports[`Connector type config checks detect connector type changes for: .gemini 4`] = ` +Object { + "flags": Object { + "default": Object { + "special": "deep", + }, + "error": [Function], + "presence": "optional", + }, + "keys": Object { + "messages": Object { + "flags": Object { + "error": [Function], + }, + "metas": Array [ + Object { + "x-oas-any-type": true, + }, + ], + "type": "any", + }, + "model": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + "signal": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-any-type": true, + }, + Object { + "x-oas-optional": true, + }, + ], + "type": "any", + }, + "stopSequences": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "items": Array [ + Object { + "flags": Object { + "error": [Function], + "presence": "optional", + }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "array", + }, + "temperature": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "number", + }, + "timeout": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "number", + }, + }, + "preferences": Object { + "stripUnknown": Object { + "objects": false, + }, + }, + "type": "object", +} +`; + +exports[`Connector type config checks detect connector type changes for: .gemini 5`] = ` +Object { + "flags": Object { + "default": Object { + "special": "deep", + }, + "error": [Function], + "presence": "optional", + }, + "keys": Object { + "messages": Object { + "flags": Object { + "error": [Function], + }, + "metas": Array [ + Object { + "x-oas-any-type": true, + }, + ], + "type": "any", + }, + "model": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + "signal": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-any-type": true, + }, + Object { + "x-oas-optional": true, + }, + ], + "type": "any", + }, + "stopSequences": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "items": Array [ + Object { + "flags": Object { + "error": [Function], + "presence": "optional", + }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "array", + }, + "temperature": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "number", + }, + "timeout": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "number", + }, + }, + "preferences": Object { + "stripUnknown": Object { + "objects": false, + }, + }, + "type": "object", +} +`; + +exports[`Connector type config checks detect connector type changes for: .gemini 6`] = ` Object { "flags": Object { "default": Object { @@ -3256,7 +3590,7 @@ Object { } `; -exports[`Connector type config checks detect connector type changes for: .gemini 5`] = ` +exports[`Connector type config checks detect connector type changes for: .gemini 7`] = ` Object { "flags": Object { "default": Object { @@ -3290,7 +3624,7 @@ Object { } `; -exports[`Connector type config checks detect connector type changes for: .gemini 6`] = ` +exports[`Connector type config checks detect connector type changes for: .gemini 8`] = ` Object { "flags": Object { "default": Object { diff --git a/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.test.ts b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.test.ts index c3624178046fce..d6c89a35ba7ffd 100644 --- a/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.test.ts +++ b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.test.ts @@ -256,6 +256,7 @@ describe('getGenAiTokenTracking', () => { }) ); }); + it('should return 0s for the total, prompt, and completion token counts when given an invalid OpenAI async iterator response', async () => { const actionTypeId = '.gen-ai'; const result = { @@ -360,6 +361,37 @@ describe('getGenAiTokenTracking', () => { expect(logger.error).toHaveBeenCalled(); }); + it('should return the total, prompt, and completion token counts when given a valid Gemini streamed response', async () => { + const actionTypeId = '.gemini'; + const result = { + actionId: '123', + status: 'ok' as const, + data: { + usageMetadata: { + promptTokenCount: 50, + candidatesTokenCount: 50, + totalTokenCount: 100, + }, + }, + }; + const validatedParams = { + subAction: 'invokeStream', + }; + + const tokenTracking = await getGenAiTokenTracking({ + actionTypeId, + logger, + result, + validatedParams, + }); + + expect(tokenTracking).toEqual({ + total_tokens: 100, + prompt_tokens: 50, + completion_tokens: 50, + }); + }); + describe('shouldTrackGenAiToken', () => { it('should be true with OpenAI action', () => { expect(shouldTrackGenAiToken('.gen-ai')).toEqual(true); @@ -367,7 +399,7 @@ describe('getGenAiTokenTracking', () => { it('should be true with bedrock action', () => { expect(shouldTrackGenAiToken('.bedrock')).toEqual(true); }); - it('should be true with Gemini action', () => { + it('should be true with gemini action', () => { expect(shouldTrackGenAiToken('.gemini')).toEqual(true); }); it('should be false with any other action', () => { diff --git a/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts index 15c5b234d24bce..41bfa28605f40f 100644 --- a/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts +++ b/x-pack/plugins/actions/server/lib/gen_ai_token_tracking.ts @@ -16,7 +16,11 @@ import { import { getTokenCountFromBedrockInvoke } from './get_token_count_from_bedrock_invoke'; import { ActionTypeExecutorRawResult } from '../../common'; import { getTokenCountFromOpenAIStream } from './get_token_count_from_openai_stream'; -import { getTokenCountFromInvokeStream, InvokeBody } from './get_token_count_from_invoke_stream'; +import { + getTokenCountFromInvokeStream, + InvokeBody, + parseGeminiStreamForUsageMetadata, +} from './get_token_count_from_invoke_stream'; interface OwnProps { actionTypeId: string; @@ -80,8 +84,37 @@ export const getGenAiTokenTracking = async ({ } } + // this is a streamed Gemini response, using the subAction invokeStream to stream the response as a simple string + if ( + validatedParams.subAction === 'invokeStream' && + result.data instanceof Readable && + actionTypeId === '.gemini' + ) { + try { + const { totalTokenCount, promptTokenCount, candidatesTokenCount } = + await parseGeminiStreamForUsageMetadata({ + responseStream: result.data.pipe(new PassThrough()), + logger, + }); + + return { + total_tokens: totalTokenCount, + prompt_tokens: promptTokenCount, + completion_tokens: candidatesTokenCount, + }; + } catch (e) { + logger.error('Failed to calculate tokens from Invoke Stream subaction streaming response'); + logger.error(e); + // silently fail and null is returned at bottom of fuction + } + } + // this is a streamed OpenAI or Bedrock response, using the subAction invokeStream to stream the response as a simple string - if (validatedParams.subAction === 'invokeStream' && result.data instanceof Readable) { + if ( + validatedParams.subAction === 'invokeStream' && + result.data instanceof Readable && + actionTypeId !== '.gemini' + ) { try { const { total, prompt, completion } = await getTokenCountFromInvokeStream({ responseStream: result.data.pipe(new PassThrough()), diff --git a/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.test.ts b/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.test.ts index dad1785538b2cf..3a2cabbb1b0e40 100644 --- a/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.test.ts +++ b/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.test.ts @@ -5,7 +5,10 @@ * 2.0. */ import { Transform } from 'stream'; -import { getTokenCountFromInvokeStream } from './get_token_count_from_invoke_stream'; +import { + getTokenCountFromInvokeStream, + parseGeminiStreamForUsageMetadata, +} from './get_token_count_from_invoke_stream'; import { loggerMock } from '@kbn/logging-mocks'; import { EventStreamCodec } from '@smithy/eventstream-codec'; import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; @@ -57,8 +60,29 @@ describe('getTokenCountFromInvokeStream', () => { ], }; + const geminiChunk = { + candidates: [ + { + content: { + role: 'model', + parts: [ + { + text: '. I be no real-life pirate, but I be mighty good at pretendin!', + }, + ], + }, + }, + ], + usageMetadata: { + promptTokenCount: 23, + candidatesTokenCount: 50, + totalTokenCount: 73, + }, + }; + const PROMPT_TOKEN_COUNT = 34; const COMPLETION_TOKEN_COUNT = 2; + describe('OpenAI stream', () => { beforeEach(() => { stream = createStreamMock(); @@ -200,6 +224,24 @@ describe('getTokenCountFromInvokeStream', () => { }); }); }); + describe('Gemini stream', () => { + beforeEach(() => { + stream = createStreamMock(); + stream.write(`data: ${JSON.stringify(geminiChunk)}`); + }); + + it('counts the prompt, completion & total tokens for Gemini response', async () => { + stream.complete(); + const tokens = await parseGeminiStreamForUsageMetadata({ + responseStream: stream.transform, + logger, + }); + + expect(tokens.promptTokenCount).toBe(23); + expect(tokens.candidatesTokenCount).toBe(50); + expect(tokens.totalTokenCount).toBe(73); + }); + }); }); function encodeBedrockResponse(completion: string | Record) { diff --git a/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.ts b/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.ts index 7fd05aa8c500dd..604e6236991365 100644 --- a/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.ts +++ b/x-pack/plugins/actions/server/lib/get_token_count_from_invoke_stream.ts @@ -20,6 +20,12 @@ export interface InvokeBody { signal?: AbortSignal; } +interface UsageMetadata { + promptTokenCount: number; + candidatesTokenCount: number; + totalTokenCount: number; +} + /** * Takes the OpenAI and Bedrock `invokeStream` sub action response stream and the request messages array as inputs. * Uses gpt-tokenizer encoding to calculate the number of tokens in the prompt and completion parts of the response stream @@ -130,6 +136,64 @@ const parseOpenAIStream: StreamParser = async (responseStream, logger, signal) = return parseOpenAIResponse(responseBody); }; +export const parseGeminiStreamForUsageMetadata = async ({ + responseStream, + logger, +}: { + responseStream: Readable; + logger: Logger; +}): Promise => { + let responseBody = ''; + + const onData = (chunk: Buffer) => { + responseBody += chunk.toString(); + }; + + responseStream.on('data', onData); + + return new Promise((resolve, reject) => { + responseStream.on('end', () => { + resolve(parseGeminiUsageMetadata(responseBody)); + }); + responseStream.on('error', (err) => { + logger.error('An error occurred while calculating streaming response tokens'); + reject(err); + }); + }); +}; + +/** Parse Gemini stream response body */ +const parseGeminiUsageMetadata = (responseBody: string): UsageMetadata => { + const parsedLines = responseBody + .split('\n') + .filter((line) => line.startsWith('data: ') && !line.endsWith('[DONE]')) + .map((line) => JSON.parse(line.replace('data: ', ''))); + + parsedLines + .filter( + ( + line + ): line is { + candidates: Array<{ + content: { role: string; parts: Array<{ text: string }> }; + finishReason: string; + safetyRatings: Array<{ category: string; probability: string }>; + }>; + } => 'candidates' in line + ) + .reduce((prev, line) => { + const parts = line.candidates[0].content?.parts; + const chunkText = parts?.map((part) => part.text).join(''); + return prev + chunkText; + }, ''); + + // Extract usage metadata from the last chunk + const lastChunk = parsedLines[parsedLines.length - 1]; + const usageMetadata = 'usageMetadata' in lastChunk ? lastChunk.usageMetadata : null; + + return usageMetadata; +}; + /** * Parses a Bedrock buffer from an array of chunks. * diff --git a/x-pack/plugins/elastic_assistant/server/lib/parse_stream.test.ts b/x-pack/plugins/elastic_assistant/server/lib/parse_stream.test.ts index 76b29fc115b4bb..959bb51c409494 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/parse_stream.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/parse_stream.test.ts @@ -99,6 +99,46 @@ describe('handleStreamStorage', () => { it('saves the error message on a failed streaming event', async () => { const tokenPromise = handleStreamStorage({ ...defaultProps, actionTypeId: '.bedrock' }); + stream.fail(); + await expect(tokenPromise).resolves.not.toThrow(); + expect(onMessageSent).toHaveBeenCalledWith( + `An error occurred while streaming the response:\n\nStream failed` + ); + }); + }); + describe('Gemini stream', () => { + beforeEach(() => { + stream = createStreamMock(); + const payload = { + candidates: [ + { + content: { + parts: [ + { + text: 'Single.', + }, + ], + }, + }, + ], + }; + stream.write(`data: ${JSON.stringify(payload)}`); + defaultProps = { + responseStream: stream.transform, + actionTypeId: '.gemini', + onMessageSent, + logger: mockLogger, + }; + }); + + it('saves the final string successful streaming event', async () => { + stream.complete(); + await handleStreamStorage(defaultProps); + expect(onMessageSent).toHaveBeenCalledWith('Single.'); + }); + it('saves the error message on a failed streaming event', async () => { + const tokenPromise = handleStreamStorage(defaultProps); + stream.fail(); await expect(tokenPromise).resolves.not.toThrow(); expect(onMessageSent).toHaveBeenCalledWith( diff --git a/x-pack/plugins/elastic_assistant/server/lib/parse_stream.ts b/x-pack/plugins/elastic_assistant/server/lib/parse_stream.ts index e42ce6e3651fb1..55be80cbb522dc 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/parse_stream.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/parse_stream.ts @@ -7,7 +7,7 @@ import { Readable } from 'stream'; import { Logger } from '@kbn/core/server'; -import { parseBedrockStream } from '@kbn/langchain/server'; +import { parseBedrockStream, parseGeminiResponse } from '@kbn/langchain/server'; type StreamParser = ( responseStream: Readable, @@ -30,7 +30,12 @@ export const handleStreamStorage = async ({ logger: Logger; }): Promise => { try { - const parser = actionTypeId === '.bedrock' ? parseBedrockStream : parseOpenAIStream; + const parser = + actionTypeId === '.bedrock' + ? parseBedrockStream + : actionTypeId === '.gemini' + ? parseGeminiStream + : parseOpenAIStream; const parsedResponse = await parser(responseStream, logger, abortSignal); if (onMessageSent) { onMessageSent(parsedResponse); @@ -87,3 +92,25 @@ const parseOpenAIResponse = (responseBody: string) => const msg = line.choices[0].delta; return prev + (msg.content || ''); }, ''); + +export const parseGeminiStream: StreamParser = async (stream, logger, abortSignal) => { + let responseBody = ''; + stream.on('data', (chunk) => { + responseBody += chunk.toString(); + }); + return new Promise((resolve, reject) => { + stream.on('end', () => { + resolve(parseGeminiResponse(responseBody)); + }); + stream.on('error', (err) => { + reject(err); + }); + if (abortSignal) { + abortSignal.addEventListener('abort', () => { + stream.destroy(); + logger.info('Gemini stream parsing was aborted.'); + resolve(parseGeminiResponse(responseBody)); + }); + } + }); +}; diff --git a/x-pack/plugins/elastic_assistant/server/routes/utils.ts b/x-pack/plugins/elastic_assistant/server/routes/utils.ts index 243befcb19271f..324d2fefa46b99 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/utils.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/utils.ts @@ -170,6 +170,7 @@ export const getLlmType = (actionTypeId: string): string | undefined => { const llmTypeDictionary: Record = { [`.gen-ai`]: `openai`, [`.bedrock`]: `bedrock`, + [`.gemini`]: `gemini`, }; return llmTypeDictionary[actionTypeId]; }; diff --git a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.test.ts b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.test.ts index 07f38251d3873b..f4257e12e1587e 100644 --- a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.test.ts +++ b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.test.ts @@ -398,6 +398,147 @@ describe('getStreamObservable', () => { error: (err) => done(err), }); }); + it('should emit loading state and chunks for Gemini', (done) => { + const chunk1 = `data: {"candidates": [{"content":{"role":"model","parts":[{"text":"My"}]}}]}\rdata: {"candidates": [{"content":{"role":"model","parts":[{"text":" new"}]}}]}`; + const chunk2 = `\rdata: {"candidates": [{"content": {"role": "model","parts": [{"text": " message"}]},"finishReason": "STOP"}],"usageMetadata": {"promptTokenCount": 23,"candidatesTokenCount": 50,"totalTokenCount": 73}}`; + const completeSubject = new Subject(); + const expectedStates: PromptObservableState[] = [ + { chunks: [], loading: true }, + { + chunks: ['My ', ' ', 'new ', ' message'], + message: 'My ', + loading: true, + }, + { + chunks: ['My ', ' ', 'new ', ' message'], + message: 'My ', + loading: true, + }, + { + chunks: ['My ', ' ', 'new ', ' message'], + message: 'My new ', + loading: true, + }, + { + chunks: ['My ', ' ', 'new ', ' message'], + message: 'My new message', + loading: false, + }, + ]; + + mockReader.read + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode(chunk1)), + }) + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode(chunk2)), + }) + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode('')), + }) + .mockResolvedValue({ + done: true, + }); + + const source = getStreamObservable({ + ...defaultProps, + actionTypeId: '.gemini', + }); + const emittedStates: PromptObservableState[] = []; + + source.subscribe({ + next: (state) => { + return emittedStates.push(state); + }, + complete: () => { + expect(emittedStates).toEqual(expectedStates); + done(); + + completeSubject.subscribe({ + next: () => { + expect(setLoading).toHaveBeenCalledWith(false); + expect(typedReader.cancel).toHaveBeenCalled(); + done(); + }, + }); + }, + error: (err) => done(err), + }); + }); + + it('should emit loading state and chunks for partial response Gemini', (done) => { + const chunk1 = `data: {"candidates": [{"content":{"role":"model","parts":[{"text":"My"}]}}]}\rdata: {"candidates": [{"content":{"role":"model","parts":[{"text":" new"}]}}]}`; + const chunk2 = `\rdata: {"candidates": [{"content": {"role": "model","parts": [{"text": " message"}]},"finishReason": "STOP"}],"usageMetadata": {"promptTokenCount": 23,"candidatesTokenCount": 50,"totalTokenCount": 73}}`; + const completeSubject = new Subject(); + const expectedStates: PromptObservableState[] = [ + { chunks: [], loading: true }, + { + chunks: ['My ', ' ', 'new ', ' message'], + message: 'My ', + loading: true, + }, + { + chunks: ['My ', ' ', 'new ', ' message'], + message: 'My ', + loading: true, + }, + { + chunks: ['My ', ' ', 'new ', ' message'], + message: 'My new ', + loading: true, + }, + { + chunks: ['My ', ' ', 'new ', ' message'], + message: 'My new message', + loading: false, + }, + ]; + + mockReader.read + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode(chunk1)), + }) + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode(chunk2)), + }) + .mockResolvedValueOnce({ + done: false, + value: new Uint8Array(new TextEncoder().encode('')), + }) + .mockResolvedValue({ + done: true, + }); + + const source = getStreamObservable({ + ...defaultProps, + actionTypeId: '.gemini', + }); + const emittedStates: PromptObservableState[] = []; + + source.subscribe({ + next: (state) => { + return emittedStates.push(state); + }, + complete: () => { + expect(emittedStates).toEqual(expectedStates); + done(); + + completeSubject.subscribe({ + next: () => { + expect(setLoading).toHaveBeenCalledWith(false); + expect(typedReader.cancel).toHaveBeenCalled(); + done(); + }, + }); + }, + error: (err) => done(err), + }); + }); it('should stream errors when reader contains errors', (done) => { const completeSubject = new Subject(); diff --git a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.ts b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.ts index 2ee9b2aa1e3d45..338ed7b661f841 100644 --- a/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.ts +++ b/x-pack/plugins/security_solution/public/assistant/get_comments/stream/stream_observable.ts @@ -19,6 +19,30 @@ interface StreamObservable { reader: ReadableStreamDefaultReader; setLoading: Dispatch>; } + +interface ResponseSchema { + candidates: Candidate[]; + usageMetadata: { + promptTokenCount: number; + candidatesTokenCount: number; + totalTokenCount: number; + }; +} + +interface Part { + text: string; +} + +interface Candidate { + content: Content; + finishReason: string; +} + +interface Content { + role: string; + parts: Part[]; +} + /** * Returns an Observable that reads data from a ReadableStream and emits values representing the state of the data processing. * @@ -44,9 +68,10 @@ export const getStreamObservable = ({ let openAIBuffer: string = ''; // Initialize an empty string to store the LangChain buffer. let langChainBuffer: string = ''; - // Initialize an empty Uint8Array to store the Bedrock concatenated buffer. let bedrockBuffer: Uint8Array = new Uint8Array(0); + // Initialize an empty string to store the Gemini buffer. + let geminiBuffer: string = ''; // read data from LangChain stream function readLangChain() { @@ -203,6 +228,54 @@ export const getStreamObservable = ({ }); } + // read data from Gemini stream + function readGemini() { + reader + .read() + .then(({ done, value }: { done: boolean; value?: Uint8Array }) => { + try { + if (done) { + if (geminiBuffer) { + chunks.push(getGeminiChunks([geminiBuffer])[0]); + } + observer.next({ + chunks, + message: chunks.join(''), + loading: false, + }); + observer.complete(); + return; + } + + const decoded = decoder.decode(value, { stream: true }); + const lines = decoded.split('\r'); + lines[0] = geminiBuffer + lines[0]; + geminiBuffer = lines.pop() || ''; + + const nextChunks = getGeminiChunks(lines); + + nextChunks.forEach((chunk: string) => { + const splitBySpace = chunk.split(' '); + for (const word of splitBySpace) { + chunks.push(`${word} `); + observer.next({ + chunks, + message: chunks.join(''), + loading: true, + }); + } + }); + } catch (err) { + observer.error(err); + return; + } + readGemini(); + }) + .catch((err) => { + observer.error(err); + }); + } + // this should never actually happen function badConnector() { observer.next({ @@ -215,6 +288,7 @@ export const getStreamObservable = ({ if (isEnabledLangChain) readLangChain(); else if (actionTypeId === '.bedrock') readBedrock(); else if (actionTypeId === '.gen-ai') readOpenAI(); + else if (actionTypeId === '.gemini') readGemini(); else badConnector(); return () => { @@ -292,4 +366,23 @@ const getLangChainChunks = (lines: string[]): string[] => return acc; }, []); +/** + * Parses an Gemini response from a string. + * @param lines + * @returns {string[]} - Parsed string array from the Gemini response. + */ +const getGeminiChunks = (lines: string[]): string[] => { + return lines + .filter((str) => !!str && str !== '[DONE]') + .map((line) => { + try { + const newLine = line.replaceAll('data: ', ''); + const geminiResponse: ResponseSchema = JSON.parse(newLine); + return geminiResponse.candidates[0]?.content.parts.map((part) => part.text).join('') ?? ''; + } catch (err) { + return ''; + } + }); +}; + export const getPlaceholderObservable = () => new Observable(); diff --git a/x-pack/plugins/stack_connectors/common/gemini/constants.ts b/x-pack/plugins/stack_connectors/common/gemini/constants.ts index 2df2e4f635e330..e0c1c6f56c65a8 100644 --- a/x-pack/plugins/stack_connectors/common/gemini/constants.ts +++ b/x-pack/plugins/stack_connectors/common/gemini/constants.ts @@ -18,6 +18,8 @@ export enum SUB_ACTION { RUN = 'run', DASHBOARD = 'getDashboard', TEST = 'test', + INVOKE_AI = 'invokeAI', + INVOKE_STREAM = 'invokeStream', } export const DEFAULT_TOKEN_LIMIT = 8192; diff --git a/x-pack/plugins/stack_connectors/common/gemini/schema.ts b/x-pack/plugins/stack_connectors/common/gemini/schema.ts index aa29f92916db91..91b523ef4853be 100644 --- a/x-pack/plugins/stack_connectors/common/gemini/schema.ts +++ b/x-pack/plugins/stack_connectors/common/gemini/schema.ts @@ -24,6 +24,8 @@ export const RunActionParamsSchema = schema.object({ model: schema.maybe(schema.string()), signal: schema.maybe(schema.any()), timeout: schema.maybe(schema.number()), + temperature: schema.maybe(schema.number()), + stopSequences: schema.maybe(schema.arrayOf(schema.string())), }); export const RunApiResponseSchema = schema.object({ @@ -50,6 +52,28 @@ export const RunActionResponseSchema = schema.object( { unknowns: 'ignore' } ); +export const InvokeAIActionParamsSchema = schema.object({ + messages: schema.any(), + model: schema.maybe(schema.string()), + temperature: schema.maybe(schema.number()), + stopSequences: schema.maybe(schema.arrayOf(schema.string())), + signal: schema.maybe(schema.any()), + timeout: schema.maybe(schema.number()), +}); + +export const InvokeAIActionResponseSchema = schema.object({ + message: schema.string(), + usageMetadata: schema.maybe( + schema.object({ + promptTokenCount: schema.number(), + candidatesTokenCount: schema.number(), + totalTokenCount: schema.number(), + }) + ), +}); + +export const StreamingResponseSchema = schema.any(); + export const DashboardActionParamsSchema = schema.object({ dashboardId: schema.string(), }); diff --git a/x-pack/plugins/stack_connectors/common/gemini/types.ts b/x-pack/plugins/stack_connectors/common/gemini/types.ts index 12d3ed4a6b1c44..bc9a96ebdfdd7e 100644 --- a/x-pack/plugins/stack_connectors/common/gemini/types.ts +++ b/x-pack/plugins/stack_connectors/common/gemini/types.ts @@ -14,6 +14,9 @@ import { RunActionParamsSchema, RunActionResponseSchema, RunApiResponseSchema, + InvokeAIActionParamsSchema, + InvokeAIActionResponseSchema, + StreamingResponseSchema, } from './schema'; export type Config = TypeOf; @@ -23,3 +26,6 @@ export type RunApiResponse = TypeOf; export type RunActionResponse = TypeOf; export type DashboardActionParams = TypeOf; export type DashboardActionResponse = TypeOf; +export type InvokeAIActionParams = TypeOf; +export type InvokeAIActionResponse = TypeOf; +export type StreamingResponse = TypeOf; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/gemini/logo.tsx b/x-pack/plugins/stack_connectors/public/connector_types/gemini/logo.tsx index dd09c31fb7079a..17da9f085e974f 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/gemini/logo.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/gemini/logo.tsx @@ -9,25 +9,15 @@ import React from 'react'; import { LogoProps } from '../types'; const Logo = (props: LogoProps) => ( - + + - - - - - - - ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts index af5fdc8cb781f8..ed825d9aecbf39 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts @@ -11,7 +11,10 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; -import { RunApiResponseSchema } from '../../../common/gemini/schema'; +import { RunApiResponseSchema, StreamingResponseSchema } from '../../../common/gemini/schema'; +import { DEFAULT_GEMINI_MODEL } from '../../../common/gemini/constants'; +import { AxiosError } from 'axios'; +import { Transform } from 'stream'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); jest.mock('@kbn/actions-plugin/server/sub_action_framework/helpers/validators', () => ({ @@ -28,14 +31,27 @@ let mockRequest: jest.Mock; describe('GeminiConnector', () => { const defaultResponse = { data: { - candidates: [{ content: { parts: [{ text: 'Paris' }] } }], - usageMetadata: { totalTokens: 0, promptTokens: 0, completionTokens: 0 }, + candidates: [{ content: { role: 'model', parts: [{ text: 'Paris' }] } }], + usageMetadata: { totalTokenCount: 0, promptTokenCount: 0, candidatesTokenCount: 0 }, }, }; + const sampleGeminiBody = { + messages: [ + { + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + }, + ], + }; + const connectorResponse = { completion: 'Paris', - usageMetadata: { totalTokens: 0, promptTokens: 0, completionTokens: 0 }, + usageMetadata: { totalTokenCount: 0, promptTokenCount: 0, candidatesTokenCount: 0 }, }; beforeEach(() => { @@ -50,7 +66,7 @@ describe('GeminiConnector', () => { configurationUtilities: actionsConfigMock.create(), config: { apiUrl: 'https://api.gemini.com', - defaultModel: 'gemini-1.5-pro-preview-0409', + defaultModel: DEFAULT_GEMINI_MODEL, gcpRegion: 'us-central1', gcpProjectID: 'my-project-12345', }, @@ -72,53 +88,228 @@ describe('GeminiConnector', () => { services: actionsMock.createServices(), }); - describe('runApi', () => { - it('should send a formatted request to the API and return the response', async () => { - const runActionParams: RunActionParams = { - body: JSON.stringify({ - messages: [ - { - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], - }, - ], + describe('Gemini', () => { + beforeEach(() => { + // @ts-ignore + connector.request = mockRequest; + }); + + describe('runApi', () => { + it('should send a formatted request to the API and return the response', async () => { + const runActionParams: RunActionParams = { + body: JSON.stringify(sampleGeminiBody), + model: DEFAULT_GEMINI_MODEL, + }; + + const response = await connector.runApi(runActionParams); + + // Assertions + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, + method: 'post', + data: JSON.stringify({ + messages: [ + { + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + }, + ], + }), + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', + }, + timeout: 60000, + responseSchema: RunApiResponseSchema, + signal: undefined, + }); + + expect(response).toEqual(connectorResponse); + }); + }); + + describe('invokeAI', () => { + const aiAssistantBody = { + messages: [ + { + role: 'user', + content: 'What is the capital of France?', + }, + ], + }; + + it('the API call is successful with correct parameters', async () => { + await connector.invokeAI(aiAssistantBody); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, + method: 'post', + responseSchema: RunApiResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - }), - model: 'test-model', + }), + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', + }, + signal: undefined, + timeout: 60000, + }); + }); + + it('signal and timeout is properly passed to runApi', async () => { + const signal = jest.fn(); + const timeout = 60000; + await connector.invokeAI({ ...aiAssistantBody, timeout, signal }); + expect(mockRequest).toHaveBeenCalledWith({ + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, + method: 'post', + responseSchema: RunApiResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, + }, + }), + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', + }, + signal, + timeout: 60000, + }); + }); + }); + + describe('invokeStream', () => { + let stream; + beforeEach(() => { + stream = createStreamMock(); + stream.write(new Uint8Array([1, 2, 3])); + mockRequest = jest.fn().mockResolvedValue({ ...defaultResponse, data: stream.transform }); + // @ts-ignore + connector.request = mockRequest; + }); + const aiAssistantBody = { + messages: [ + { + role: 'user', + content: 'What is the capital of France?', + }, + ], }; - const response = await connector.runApi(runActionParams); + it('the API call is successful with correct request parameters', async () => { + await connector.invokeStream(aiAssistantBody); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, + }, + }), + responseType: 'stream', + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', + }, + signal: undefined, + timeout: 60000, + }); + }); - // Assertions - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/test-model:generateContent', - method: 'post', - data: JSON.stringify({ - messages: [ - { - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], - }, - ], + it('signal and timeout is properly passed to streamApi', async () => { + const signal = jest.fn(); + const timeout = 60000; + await connector.invokeStream({ ...aiAssistantBody, timeout, signal }); + expect(mockRequest).toHaveBeenCalledWith({ + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - }), - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', - }, - timeout: 60000, - responseSchema: RunApiResponseSchema, - signal: undefined, + }), + responseType: 'stream', + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', + }, + signal, + timeout: 60000, + }); + }); + }); + + describe('getResponseErrorMessage', () => { + it('returns an unknown error message', () => { + // @ts-expect-error expects an axios error as the parameter + expect(connector.getResponseErrorMessage({})).toEqual( + `Unexpected API Error: - Unknown error` + ); }); - expect(response).toEqual(connectorResponse); + it('returns the error.message', () => { + // @ts-expect-error expects an axios error as the parameter + expect(connector.getResponseErrorMessage({ message: 'a message' })).toEqual( + `Unexpected API Error: - a message` + ); + }); + + it('returns the error.response.data.error.message', () => { + const err = { + response: { + headers: {}, + status: 404, + statusText: 'Resource Not Found', + data: { + message: 'Resource not found', + }, + }, + } as AxiosError<{ message?: string }>; + expect( + // @ts-expect-error expects an axios error as the parameter + connector.getResponseErrorMessage(err) + ).toEqual(`API Error: Resource Not Found - Resource not found`); + }); }); }); @@ -190,3 +381,21 @@ describe('GeminiConnector', () => { }); }); }); + +function createStreamMock() { + const transform: Transform = new Transform({}); + + return { + write: (data: Uint8Array) => { + transform.push(data); + }, + fail: () => { + transform.emit('error', new Error('Stream failed')); + transform.end(); + }, + transform, + complete: () => { + transform.end(); + }, + }; +} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts index 61b8834927a482..323b13d3b768e3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts @@ -7,23 +7,37 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import { AxiosError, Method } from 'axios'; +import { PassThrough } from 'stream'; +import { IncomingMessage } from 'http'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { getGoogleOAuthJwtAccessToken } from '@kbn/actions-plugin/server/lib/get_gcp_oauth_access_token'; import { Logger } from '@kbn/core/server'; import { ConnectorTokenClientContract } from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { RunActionParamsSchema, RunApiResponseSchema } from '../../../common/gemini/schema'; +import { + RunActionParamsSchema, + RunApiResponseSchema, + InvokeAIActionParamsSchema, + StreamingResponseSchema, +} from '../../../common/gemini/schema'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; - import { Config, Secrets, RunActionParams, RunActionResponse, RunApiResponse, + DashboardActionParams, + DashboardActionResponse, + StreamingResponse, + InvokeAIActionParams, + InvokeAIActionResponse, } from '../../../common/gemini/types'; -import { SUB_ACTION, DEFAULT_TIMEOUT_MS } from '../../../common/gemini/constants'; -import { DashboardActionParams, DashboardActionResponse } from '../../../common/gemini/types'; +import { + SUB_ACTION, + DEFAULT_TIMEOUT_MS, + DEFAULT_TOKEN_LIMIT, +} from '../../../common/gemini/constants'; import { DashboardActionParamsSchema } from '../../../common/gemini/schema'; export interface GetAxiosInstanceOpts { @@ -35,6 +49,25 @@ export interface GetAxiosInstanceOpts { configurationUtilities: ActionsConfigurationUtilities; } +/** Interfaces to define Gemini model response type */ + +interface MessagePart { + text: string; +} + +interface MessageContent { + role: string; + parts: MessagePart[]; +} + +interface Payload { + contents: MessageContent[]; + generation_config: { + temperature: number; + maxOutputTokens: number; + }; +} + export class GeminiConnector extends SubActionConnector { private url; private model; @@ -74,6 +107,18 @@ export class GeminiConnector extends SubActionConnector { method: 'runApi', schema: RunActionParamsSchema, }); + + this.registerSubAction({ + name: SUB_ACTION.INVOKE_AI, + method: 'invokeAI', + schema: InvokeAIActionParamsSchema, + }); + + this.registerSubAction({ + name: SUB_ACTION.INVOKE_STREAM, + method: 'invokeStream', + schema: InvokeAIActionParamsSchema, + }); } protected getResponseErrorMessage(error: AxiosError<{ message?: string }>): string { @@ -185,4 +230,111 @@ export class GeminiConnector extends SubActionConnector { return { completion: completionText, usageMetadata }; } + + private async streamAPI({ + body, + model: reqModel, + signal, + timeout, + }: RunActionParams): Promise { + const currentModel = reqModel ?? this.model; + const path = `/v1/projects/${this.gcpProjectID}/locations/${this.gcpRegion}/publishers/google/models/${currentModel}:streamGenerateContent?alt=sse`; + const token = await this.getAccessToken(); + + const response = await this.request({ + url: `${this.url}${path}`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: body, + responseType: 'stream', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + signal, + timeout: timeout ?? DEFAULT_TIMEOUT_MS, + }); + + return response.data.pipe(new PassThrough()); + } + + public async invokeAI({ + messages, + model, + temperature = 0, + signal, + timeout, + }: InvokeAIActionParams): Promise { + const res = await this.runApi({ + body: JSON.stringify(formatGeminiPayload(messages, temperature)), + model, + signal, + timeout, + }); + + return { message: res.completion, usageMetadata: res.usageMetadata }; + } + + /** + * takes in an array of messages and a model as inputs. It calls the streamApi method to make a + * request to the Gemini API with the formatted messages and model. It then returns a Transform stream + * that pipes the response from the API through the transformToString function, + * which parses the proprietary response into a string of the response text alone + * @param messages An array of messages to be sent to the API + * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. + */ + public async invokeStream({ + messages, + model, + stopSequences, + temperature = 0, + signal, + timeout, + }: InvokeAIActionParams): Promise { + const res = (await this.streamAPI({ + body: JSON.stringify(formatGeminiPayload(messages, temperature)), + model, + stopSequences, + signal, + timeout, + })) as unknown as IncomingMessage; + return res; + } } + +/** Format the json body to meet Gemini payload requirements */ +const formatGeminiPayload = ( + data: Array<{ role: string; content: string }>, + temperature: number +): Payload => { + const payload: Payload = { + contents: [], + generation_config: { + temperature, + maxOutputTokens: DEFAULT_TOKEN_LIMIT, + }, + }; + let previousRole: string | null = null; + + for (const row of data) { + const correctRole = row.role === 'assistant' ? 'model' : 'user'; + if (correctRole === 'user' && previousRole === 'user') { + /** Append to the previous 'user' content + * This is to ensure that multiturn requests alternate between user and model + */ + payload.contents[payload.contents.length - 1].parts[0].text += ` ${row.content}`; + } else { + // Add a new entry + payload.contents.push({ + role: correctRole, + parts: [ + { + text: row.content, + }, + ], + }); + } + previousRole = correctRole; + } + return payload; +}; From dce29e277b27f19b13ce90c4a74cac66c9fc2c79 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Mon, 17 Jun 2024 19:57:47 +0200 Subject: [PATCH 003/123] [kbn-test] call Kibana API to fetch current user profile (#186279) Related to #185870 In this PR I move user_profile fetching out of SAML session creation to its `sessionManager.getUserData()`: - rely on Kibana Security API for both local/Kibana CI and MKI cases (currently it is cloud and cached on saml session creation) - do not cache profile data in test service, Kibana API is fast enough I deleted the tests that no longer relevant --- packages/kbn-test/src/auth/saml_auth.ts | 11 ++- packages/kbn-test/src/auth/session_manager.ts | 17 ++++- .../kbn-test/src/auth/sesson_manager.test.ts | 71 ++++++++++++++----- .../common/platform_security/index.ts | 1 - .../platform_security/request_as_viewer.ts | 36 ---------- .../page_objects/svl_common_page.ts | 6 +- .../common/platform_security/index.ts | 1 - .../user_profiles/user_profiles.ts | 2 +- .../platform_security/viewer_role_login.ts | 32 --------- .../shared/services/svl_user_manager.ts | 4 ++ 10 files changed, 81 insertions(+), 100 deletions(-) delete mode 100644 x-pack/test_serverless/api_integration/test_suites/common/platform_security/request_as_viewer.ts delete mode 100644 x-pack/test_serverless/functional/test_suites/common/platform_security/viewer_role_login.ts diff --git a/packages/kbn-test/src/auth/saml_auth.ts b/packages/kbn-test/src/auth/saml_auth.ts index a88d11c6a5bc90..99343c8c6912b6 100644 --- a/packages/kbn-test/src/auth/saml_auth.ts +++ b/packages/kbn-test/src/auth/saml_auth.ts @@ -24,11 +24,9 @@ import { export class Session { readonly cookie; readonly email; - readonly fullname; - constructor(cookie: Cookie, email: string, fullname: string) { + constructor(cookie: Cookie, email: string) { this.cookie = cookie; this.email = email; - this.fullname = fullname; } getCookieValue() { @@ -239,7 +237,7 @@ export const finishSAMLHandshake = async ({ ); }; -const getSecurityProfile = async ({ +export const getSecurityProfile = async ({ kbnHost, cookie, log, @@ -274,8 +272,7 @@ export const createCloudSAMLSession = async (params: CloudSamlSessionParams) => const { location, sid } = await createSAMLRequest(kbnHost, kbnVersion, log); const samlResponse = await createSAMLResponse({ location, ecSession, email, kbnHost, log }); const cookie = await finishSAMLHandshake({ kbnHost, samlResponse, sid, log }); - const userProfile = await getSecurityProfile({ kbnHost, cookie, log }); - return new Session(cookie, email, userProfile.full_name); + return new Session(cookie, email); }; export const createLocalSAMLSession = async (params: LocalSamlSessionParams) => { @@ -288,5 +285,5 @@ export const createLocalSAMLSession = async (params: LocalSamlSessionParams) => roles: [role], }); const cookie = await finishSAMLHandshake({ kbnHost, samlResponse, log }); - return new Session(cookie, email, fullname); + return new Session(cookie, email); }; diff --git a/packages/kbn-test/src/auth/session_manager.ts b/packages/kbn-test/src/auth/session_manager.ts index a8edca981c1d4d..1783c3f389aa1f 100644 --- a/packages/kbn-test/src/auth/session_manager.ts +++ b/packages/kbn-test/src/auth/session_manager.ts @@ -13,7 +13,12 @@ import { resolve } from 'path'; import Url from 'url'; import { KbnClient } from '../kbn_client'; import { readCloudUsersFromFile } from './helper'; -import { createCloudSAMLSession, createLocalSAMLSession, Session } from './saml_auth'; +import { + createCloudSAMLSession, + createLocalSAMLSession, + getSecurityProfile, + Session, +} from './saml_auth'; import { Role, User } from './types'; export interface HostOptions { @@ -146,8 +151,14 @@ export class SamlSessionManager { return session.getCookieValue(); } + async getEmail(role: string) { + const session = await this.getSessionByRole(role); + return session.email; + } + async getUserData(role: string) { - const { email, fullname } = await this.getSessionByRole(role); - return { email, fullname }; + const { cookie } = await this.getSessionByRole(role); + const profileData = await getSecurityProfile({ kbnHost: this.kbnHost, cookie, log: this.log }); + return profileData; } } diff --git a/packages/kbn-test/src/auth/sesson_manager.test.ts b/packages/kbn-test/src/auth/sesson_manager.test.ts index f0679917654a0d..df037ebdf04e48 100644 --- a/packages/kbn-test/src/auth/sesson_manager.test.ts +++ b/packages/kbn-test/src/auth/sesson_manager.test.ts @@ -12,7 +12,7 @@ import { Session } from './saml_auth'; import { SamlSessionManager } from './session_manager'; import * as samlAuth from './saml_auth'; import * as helper from './helper'; -import { Role, User } from './types'; +import { Role, User, UserProfile } from './types'; import { SERVERLESS_ROLES_ROOT_PATH } from '@kbn/es'; const log = new ToolingLog(); @@ -23,6 +23,7 @@ const roleEditor = 'editor'; const createLocalSAMLSessionMock = jest.spyOn(samlAuth, 'createLocalSAMLSession'); const createCloudSAMLSessionMock = jest.spyOn(samlAuth, 'createCloudSAMLSession'); +const getSecurityProfileMock = jest.spyOn(samlAuth, 'getSecurityProfile'); const readCloudUsersFromFileMock = jest.spyOn(helper, 'readCloudUsersFromFile'); const isValidHostnameMock = jest.spyOn(helper, 'isValidHostname'); @@ -42,7 +43,7 @@ describe('SamlSessionManager', () => { .KbnClient.mockImplementation(() => ({ version: { get } })); get.mockImplementation(() => Promise.resolve('8.12.0')); - createLocalSAMLSessionMock.mockResolvedValue(new Session(cookieInstance, email, fullname)); + createLocalSAMLSessionMock.mockResolvedValue(new Session(cookieInstance, testEmail)); }); const hostOptions = { @@ -59,8 +60,8 @@ describe('SamlSessionManager', () => { log, supportedRoles, }; - const email = 'testuser@elastic.com'; - const fullname = 'Test User'; + const testEmail = 'testuser@elastic.com'; + const testFullname = 'Test User'; const cookieInstance = Cookie.parse( 'sid=kbn_cookie_value; Path=/; Expires=Wed, 01 Oct 2023 07:00:00 GMT' )!; @@ -91,10 +92,26 @@ describe('SamlSessionManager', () => { expect(createCloudSAMLSessionMock.mock.calls).toHaveLength(0); }); - test(`'getUserData' should return the correct email & fullname`, async () => { + test(`'getEmail' return the correct email`, async () => { const samlSessionManager = new SamlSessionManager(samlSessionManagerOptions); - const data = await samlSessionManager.getUserData(roleViewer); - expect(data).toEqual({ email, fullname }); + const email = await samlSessionManager.getEmail(roleEditor); + expect(email).toBe(testEmail); + }); + + test(`'getUserData' should call security API and return user profile data`, async () => { + const testData: UserProfile = { + username: '6ta90xc', + roles: [roleEditor], + full_name: testFullname, + email: testEmail, + enabled: true, + elastic_cloud_user: false, + }; + getSecurityProfileMock.mockResolvedValueOnce(testData); + const samlSessionManager = new SamlSessionManager(samlSessionManagerOptions); + const userData = await samlSessionManager.getUserData(roleViewer); + + expect(userData).toEqual(testData); }); test(`throws error when role is not in 'supportedRoles'`, async () => { @@ -117,6 +134,15 @@ describe('SamlSessionManager', () => { test(`doesn't throw error when supportedRoles is not defined`, async () => { const nonExistingRole = 'tester'; + const testData: UserProfile = { + username: '6ta90xc', + roles: [nonExistingRole], + full_name: testFullname, + email: testEmail, + enabled: true, + elastic_cloud_user: false, + }; + getSecurityProfileMock.mockResolvedValueOnce(testData); const samlSessionManager = new SamlSessionManager({ hostOptions, log, @@ -127,6 +153,7 @@ describe('SamlSessionManager', () => { await samlSessionManager.getUserData(nonExistingRole); expect(createLocalSAMLSessionMock.mock.calls).toHaveLength(1); expect(createCloudSAMLSessionMock.mock.calls).toHaveLength(0); + expect(getSecurityProfileMock.mock.calls).toHaveLength(1); }); }); @@ -184,9 +211,7 @@ describe('SamlSessionManager', () => { .KbnClient.mockImplementation(() => ({ version: { get } })); get.mockImplementationOnce(() => Promise.resolve('8.12.0')); - createCloudSAMLSessionMock.mockResolvedValue( - new Session(cloudCookieInstance, cloudEmail, cloudFullname) - ); + createCloudSAMLSessionMock.mockResolvedValue(new Session(cloudCookieInstance, cloudEmail)); readCloudUsersFromFileMock.mockReturnValue(cloudUsers); }); @@ -201,9 +226,7 @@ describe('SamlSessionManager', () => { test(`'getSessionCookieForRole' should return the actual cookie value`, async () => { const samlSessionManager = new SamlSessionManager(samlSessionManagerOptions); - createCloudSAMLSessionMock.mockResolvedValue( - new Session(cloudCookieInstance, cloudEmail, cloudFullname) - ); + createCloudSAMLSessionMock.mockResolvedValue(new Session(cloudCookieInstance, cloudEmail)); const cookie = await samlSessionManager.getSessionCookieForRole(roleViewer); expect(cookie).toBe(cloudCookieInstance.value); }); @@ -223,10 +246,26 @@ describe('SamlSessionManager', () => { expect(createCloudSAMLSessionMock.mock.calls).toHaveLength(2); }); - test(`'getUserData' should return the correct email & fullname`, async () => { + test(`'getEmail' return the correct email`, async () => { const samlSessionManager = new SamlSessionManager(samlSessionManagerOptions); - const data = await samlSessionManager.getUserData(roleViewer); - expect(data).toEqual({ email: cloudEmail, fullname: cloudFullname }); + const email = await samlSessionManager.getEmail(roleViewer); + expect(email).toBe(cloudEmail); + }); + + test(`'getUserData' should call security API and return user profile data`, async () => { + const testData: UserProfile = { + username: '92qab123', + roles: [roleViewer], + full_name: cloudFullname, + email: cloudEmail, + enabled: true, + elastic_cloud_user: true, + }; + getSecurityProfileMock.mockResolvedValueOnce(testData); + const samlSessionManager = new SamlSessionManager(samlSessionManagerOptions); + const userData = await samlSessionManager.getUserData(roleViewer); + + expect(userData).toEqual(testData); }); test(`throws error for non-existing role when 'supportedRoles' is defined`, async () => { diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts index fab6e47e87969a..e5f3f4a86a9235 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/index.ts @@ -22,7 +22,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./role_mappings')); loadTestFile(require.resolve('./sessions')); loadTestFile(require.resolve('./users')); - loadTestFile(require.resolve('./request_as_viewer')); loadTestFile(require.resolve('./user_profiles')); loadTestFile(require.resolve('./views')); loadTestFile(require.resolve('./feature_check')); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/request_as_viewer.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/request_as_viewer.ts deleted file mode 100644 index 7931f28f55df78..00000000000000 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/request_as_viewer.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import type { FtrProviderContext } from '../../../ftr_provider_context'; - -export default function ({ getService }: FtrProviderContext) { - describe('security/me as viewer', () => { - const svlUserManager = getService('svlUserManager'); - const svlCommonApi = getService('svlCommonApi'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); - let credentials: { Cookie: string }; - - before(async () => { - // get auth header for Viewer role - credentials = await svlUserManager.getApiCredentialsForRole('viewer'); - }); - - it('returns valid user data for authenticated request', async () => { - const { body, status } = await supertestWithoutAuth - .get('/internal/security/me') - .set(svlCommonApi.getInternalRequestHeader()) - .set(credentials); - - const userData = await svlUserManager.getUserData('viewer'); - - expect(status).to.be(200); - expect(body.full_name).to.be(userData.fullname); - expect(body.email).to.be(userData.email); - }); - }); -} diff --git a/x-pack/test_serverless/functional/page_objects/svl_common_page.ts b/x-pack/test_serverless/functional/page_objects/svl_common_page.ts index 49113e5565435d..827821c128daa2 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_common_page.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_common_page.ts @@ -100,14 +100,14 @@ export function SvlCommonPageProvider({ getService, getPageObjects }: FtrProvide .set(svlCommonApi.getInternalRequestHeader()) .set({ Cookie: `sid=${browserCookies[0].value}` }); - const userData = await svlUserManager.getUserData(role); + const email = await svlUserManager.getEmail(role); // email returned from API call must match the email for the specified role - if (body.email === userData.email) { + if (body.email === email) { log.debug(`The new cookie is properly set for '${role}' role`); } else { log.debug(`API response body: ${JSON.stringify(body)}`); throw new Error( - `Cookie is not set properly, expected email is '${userData.email}', but found '${body.email}'` + `Cookie is not set properly, expected email is '${email}', but found '${body.email}'` ); } // Verifying that we are logged in diff --git a/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts index 7427384fc73bf1..bbb66a98418682 100644 --- a/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/platform_security/index.ts @@ -9,7 +9,6 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Serverless Common UI - Platform Security', function () { - loadTestFile(require.resolve('./viewer_role_login')); loadTestFile(require.resolve('./api_keys')); loadTestFile(require.resolve('./navigation/avatar_menu')); loadTestFile(require.resolve('./user_profiles/user_profiles')); diff --git a/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts index c9c61d5d3a6a95..50313bc4da7cf9 100644 --- a/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts +++ b/x-pack/test_serverless/functional/test_suites/common/platform_security/user_profiles/user_profiles.ts @@ -33,7 +33,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const actualFullname = await pageObjects.userProfiles.getProfileFullname(); const actualEmail = await pageObjects.userProfiles.getProfileEmail(); - expect(actualFullname).to.be(userData.fullname); + expect(actualFullname).to.be(userData.full_name); expect(actualEmail).to.be(userData.email); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/platform_security/viewer_role_login.ts b/x-pack/test_serverless/functional/test_suites/common/platform_security/viewer_role_login.ts deleted file mode 100644 index 767abe540c2f50..00000000000000 --- a/x-pack/test_serverless/functional/test_suites/common/platform_security/viewer_role_login.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../ftr_provider_context'; - -const VIEWER_ROLE = 'viewer'; - -export default function ({ getPageObject, getService }: FtrProviderContext) { - describe(`Login as ${VIEWER_ROLE}`, function () { - const svlCommonPage = getPageObject('svlCommonPage'); - const testSubjects = getService('testSubjects'); - const svlUserManager = getService('svlUserManager'); - - before(async () => { - await svlCommonPage.loginWithRole(VIEWER_ROLE); - }); - - it('should be able to see correct profile', async () => { - await svlCommonPage.assertProjectHeaderExists(); - await svlCommonPage.assertUserAvatarExists(); - await svlCommonPage.clickUserAvatar(); - await svlCommonPage.assertUserMenuExists(); - const actualFullname = await testSubjects.getVisibleText('contextMenuPanelTitle'); - const userData = await svlUserManager.getUserData(VIEWER_ROLE); - expect(actualFullname).to.be(userData.fullname); - }); - }); -} diff --git a/x-pack/test_serverless/shared/services/svl_user_manager.ts b/x-pack/test_serverless/shared/services/svl_user_manager.ts index 3568da0c6b87b1..12fa18eee66731 100644 --- a/x-pack/test_serverless/shared/services/svl_user_manager.ts +++ b/x-pack/test_serverless/shared/services/svl_user_manager.ts @@ -78,6 +78,10 @@ export function SvlUserManagerProvider({ getService }: FtrProviderContext) { async getApiCredentialsForRole(role: string) { return sessionManager.getApiCredentialsForRole(role); }, + async getEmail(role: string) { + return sessionManager.getEmail(role); + }, + async getUserData(role: string) { return sessionManager.getUserData(role); }, From 51e84f49ba0069793e763048cfb4b4a692ed5fb1 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Mon, 17 Jun 2024 11:18:39 -0700 Subject: [PATCH 004/123] [DOCS] Standardize advanced setting deprecation admonitions (#186314) --- docs/management/advanced-options.asciidoc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 5de4ea45c32047..bad18a706cbf29 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -268,7 +268,8 @@ the `xpack.banners.backgroundColor` configuration property. [horizontal] [[xpackdashboardmode-roles]]`xpackDashboardMode:roles`:: -**Deprecated. Use <> instead.** +deprecated:[7.7.0] +Deprecated; use <> instead. The roles that belong to <>. [float] @@ -545,7 +546,7 @@ because requests can be spread across all shard copies. However, results might be inconsistent because different shards might be in different refresh states. [[search-includefrozen]]`search:includeFrozen`:: -**This setting is deprecated and will not be supported as of 9.0.** +deprecated:[7.16.0] Includes {ref}/frozen-indices.html[frozen indices] in results. Searching through frozen indices might increase the search time. This setting is off by default. Users must opt-in to include frozen indices. @@ -622,11 +623,11 @@ of buckets to try to represent. [horizontal] [[visualization-colormapping]]`visualization:colorMapping`:: -**This setting is deprecated and will not be supported in a future version.** +deprecated:[7.11.0] Maps values to specific colors in charts using the *Compatibility* palette. [[visualization-uselegacytimeaxis]]`visualization:useLegacyTimeAxis`:: -**This setting is deprecated and will not be supported in a future version.** +deprecated:[8.10.0] Enables the legacy time axis for charts in Lens, Discover, Visualize and TSVB [[visualization-heatmap-maxbuckets]]`visualization:heatmap:maxBuckets`:: From c091dd89ff8f39b5a74682cfbe06b6c472a7130c Mon Sep 17 00:00:00 2001 From: Saarika Bhasi <55930906+saarikabhasi@users.noreply.github.com> Date: Mon, 17 Jun 2024 17:12:13 -0400 Subject: [PATCH 005/123] [Index management] Make create Inference endpoint from flyout async task (#184615) Currently, when a new inference endpoint is created from inference flyout, the flyout stays open until the endpoint is created. This may take long time when Elasticsearch models - `.elser_model_2` and `.multilingual-e5-small` is to be downloaded, deployed and inference endpoint is to be created. In this PR, When a new inference endpoint is saved, inference flyout is closed and the new inference endpoint is created by a callback function in the component. **Screen Recording** https://github.com/elastic/kibana/assets/55930906/8eabba1a-108a-4bf2-813a-66ceb291467c **Testing instructions** **update Elasticsearch to latest (only to test save mappings)** Since ES changes for the semantic_text has been merged to main, this can be tested against running ES from source or from latest snapshot - Update local branch with latest Elasticsearch changes from main - Run the elasticsearch: ./gradlew :run -Drun.license_type=trial - Manual test in UI **Frontend** - enable` xpack.index_management.dev.enableSemanticText` to true in `config/kibana.dev.yml` - Add a new field with type - Semantic_text - Click on drop down menu below `Select an inference endpoint` - Click Add inference Endpoint - Type new inference endpoint name and click Save endpoint - Save endpoint button should close the flyout - A new success notification toasts is shown with text "1 model is being deployed on your ml_node." - Add new field - Click Save mappings - should show a modal with model deployment status - After new endpoint is created, refresh button should hide the modal and save mappings should update mappings --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/inference_flyout_wrapper.tsx | 2 +- .../ml/inference_integration_flyout/types.ts | 2 +- .../helpers/http_requests.ts | 4 + .../index_details_page.helpers.ts | 46 +++- .../index_details_page.test.tsx | 154 ++++++++--- .../select_inference_id.test.tsx | 15 +- .../reference_field_selects.tsx | 13 +- .../field_parameters/select_inference_id.tsx | 118 ++++----- .../fields/create_field/create_field.tsx | 35 ++- .../semantic_text/use_semantic_text.test.ts | 241 +++++++++++++----- .../semantic_text/use_semantic_text.ts | 172 ++++++------- .../constants/field_options.tsx | 1 + .../mappings_editor/types/document_fields.ts | 15 ++ .../trained_models_deployment_modal.tsx | 4 +- ...ils_page_mappings_model_management.test.ts | 4 - ..._details_page_mappings_model_management.ts | 30 ++- .../hooks/use_ml_model_status_toasts.ts | 36 +++ x-pack/plugins/index_management/tsconfig.json | 4 +- 18 files changed, 594 insertions(+), 302 deletions(-) rename x-pack/plugins/index_management/{public/application/components/mappings_editor/components/document_fields/field_parameters => __jest__/client_integration/index_details_page}/select_inference_id.test.tsx (80%) create mode 100644 x-pack/plugins/index_management/public/hooks/use_ml_model_status_toasts.ts diff --git a/x-pack/packages/ml/inference_integration_flyout/components/inference_flyout_wrapper.tsx b/x-pack/packages/ml/inference_integration_flyout/components/inference_flyout_wrapper.tsx index d5e17de1ef4c72..d66540feccff1d 100644 --- a/x-pack/packages/ml/inference_integration_flyout/components/inference_flyout_wrapper.tsx +++ b/x-pack/packages/ml/inference_integration_flyout/components/inference_flyout_wrapper.tsx @@ -78,7 +78,7 @@ export interface SaveMappingOnClick { taskType: InferenceTaskType, modelConfig: ModelConfig ) => void; - isCreateInferenceApiLoading: boolean; + isCreateInferenceApiLoading?: boolean; } export interface DocumentationProps { elserv2documentationUrl?: string; diff --git a/x-pack/packages/ml/inference_integration_flyout/types.ts b/x-pack/packages/ml/inference_integration_flyout/types.ts index 849706b12a84f7..900778e2546863 100644 --- a/x-pack/packages/ml/inference_integration_flyout/types.ts +++ b/x-pack/packages/ml/inference_integration_flyout/types.ts @@ -54,7 +54,7 @@ export interface ElasticsearchService { export enum Service { cohere = 'cohere', elser = 'elser', - huggingFace = 'huggingFace', + huggingFace = 'hugging_face', openai = 'openai', elasticsearch = 'elasticsearch', } diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts index 235e5090a26959..8bd8672b8fbba9 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts @@ -209,6 +209,9 @@ const registerHttpRequestMockHelpers = ( const setCreateIndexResponse = (response?: HttpResponse, error?: ResponseError) => mockResponse('PUT', `${INTERNAL_API_BASE_PATH}/indices/create`, response, error); + const setInferenceModels = (response?: HttpResponse, error?: ResponseError) => + mockResponse('GET', `${API_BASE_PATH}/inference/all`, response, error); + return { setLoadTemplatesResponse, setLoadIndicesResponse, @@ -238,6 +241,7 @@ const registerHttpRequestMockHelpers = ( setGetFieldsFromIndices, setGetPrivilegesResponse, setCreateEnrichPolicy, + setInferenceModels, }; }; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.helpers.ts index 5a15772d5e16ab..91dd4d26c2a5b7 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.helpers.ts @@ -13,7 +13,7 @@ import { } from '@kbn/test-jest-helpers'; import { HttpSetup } from '@kbn/core/public'; import { act } from 'react-dom/test-utils'; - +import { keys } from '@elastic/eui'; import { IndexDetailsTabId } from '../../../common/constants'; import { IndexDetailsPage } from '../../../public/application/sections/home/index_list/details_page'; import { WithAppDependencies } from '../helpers'; @@ -56,6 +56,12 @@ export interface IndexDetailsPageTestBed extends TestBed { setSearchBarValue: (searchValue: string) => Promise; findSearchResult: () => string; isSemanticTextBannerVisible: () => boolean; + selectSemanticTextField: (name: string, type: string) => Promise; + isReferenceFieldVisible: () => void; + selectInferenceIdButtonExists: () => void; + openSelectInferencePopover: () => void; + expectDefaultInferenceModelToExists: () => void; + expectCustomInferenceModelToExists: (customInference: string) => Promise; }; settings: { getCodeBlockContent: () => string; @@ -228,7 +234,7 @@ export const setup = async ({ component.update(); }, selectFilterFieldType: async (fieldType: string) => { - expect(testBed.exists('indexDetailsMappingsSelectFilter-text')).toBe(true); + expect(testBed.exists(fieldType)).toBe(true); await act(async () => { find(fieldType).simulate('click'); }); @@ -287,6 +293,7 @@ export const setup = async ({ await act(async () => { expect(exists('createFieldForm.addButton')).toBe(true); + expect(find('createFieldForm.addButton').props().disabled).toBeFalsy(); find('createFieldForm.addButton').simulate('click'); }); @@ -294,6 +301,41 @@ export const setup = async ({ } } }, + selectSemanticTextField: async (name: string, type: string) => { + expect(exists('comboBoxSearchInput')).toBe(true); + + const { form } = testBed; + form.setInputValue('nameParameterInput', name); + form.setInputValue('comboBoxSearchInput', type); + await act(async () => { + find('comboBoxSearchInput').simulate('keydown', { key: keys.ENTER }); + }); + // select semantic_text field + await act(async () => { + expect(exists('fieldTypesOptions-semantic_text')).toBe(true); + find('fieldTypesOptions-semantic_text').simulate('click'); + expect(exists('fieldTypesOptions-semantic_text')).toBe(false); + }); + }, + isReferenceFieldVisible: async () => { + expect(exists('referenceField.select')).toBe(true); + }, + selectInferenceIdButtonExists: async () => { + expect(exists('selectInferenceId')).toBe(true); + expect(exists('inferenceIdButton')).toBe(true); + find('inferenceIdButton').simulate('click'); + }, + openSelectInferencePopover: async () => { + expect(exists('addInferenceEndpointButton')).toBe(true); + expect(exists('manageInferenceEndpointButton')).toBe(true); + }, + expectDefaultInferenceModelToExists: async () => { + expect(exists('default-inference_elser_model_2')).toBe(true); + expect(exists('default-inference_e5')).toBe(true); + }, + expectCustomInferenceModelToExists: async (customInference: string) => { + expect(exists(customInference)).toBe(true); + }, }; const settings = { diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx index 37e2799678e79b..18f43807041ffd 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx @@ -18,6 +18,7 @@ import { breadcrumbService, IndexManagementBreadcrumb, } from '../../../public/application/services/breadcrumbs'; +import { documentationService } from '../../../public/application/services/documentation'; import { humanizeTimeStamp } from '../../../public/application/sections/home/data_stream_list/humanize_time_stamp'; import { createDataStreamPayload } from '../home/data_streams_tab.helpers'; import { @@ -58,6 +59,7 @@ describe('', () => { let httpSetup: ReturnType['httpSetup']; let httpRequestsMockHelpers: ReturnType['httpRequestsMockHelpers']; jest.spyOn(breadcrumbService, 'setBreadcrumbs'); + jest.spyOn(documentationService, 'setup'); beforeEach(async () => { const mockEnvironment = setupEnvironment(); @@ -571,14 +573,9 @@ describe('', () => { }, }; beforeEach(async () => { - httpRequestsMockHelpers.setUpdateIndexMappingsResponse(testIndexName, { - acknowledged: true, - }); - await act(async () => { testBed = await setup({ httpSetup }); }); - testBed.component.update(); await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Mappings); await testBed.actions.mappings.clickAddFieldButton(); @@ -634,43 +631,6 @@ describe('', () => { ); }); - it('can add a semantic_text field and can save mappings', async () => { - const mockIndexMappingResponseForSemanticText: any = { - ...testIndexMappings.mappings, - properties: { - ...testIndexMappings.mappings.properties, - sem: { - type: 'semantic_text', - inference_id: 'my-elser', - }, - }, - }; - httpRequestsMockHelpers.setLoadIndexMappingResponse(testIndexName, { - mappings: mockIndexMappingResponseForSemanticText, - }); - await testBed.actions.mappings.addNewMappingFieldNameAndType([ - { name: 'sem', type: 'semantic_text' }, - ]); - await testBed.actions.mappings.clickSaveMappingsButton(); - // add field button is available again - expect(testBed.exists('indexDetailsMappingsAddField')).toBe(true); - expect(testBed.find('semField-datatype').props()['data-type-value']).toBe('semantic_text'); - expect(httpSetup.get).toHaveBeenCalledTimes(5); - expect(httpSetup.get).toHaveBeenLastCalledWith( - `${API_BASE_PATH}/mapping/${testIndexName}`, - requestOptions - ); - // refresh mappings and page re-renders - expect(testBed.exists('indexDetailsMappingsAddField')).toBe(true); - expect(testBed.actions.mappings.isSearchBarDisabled()).toBe(false); - const treeViewContent = testBed.actions.mappings.getTreeViewContent('semField'); - expect(treeViewContent).toContain('sem'); - await testBed.actions.mappings.clickToggleViewButton(); - const jsonContent = testBed.actions.mappings.getCodeBlockContent(); - expect(jsonContent).toEqual( - JSON.stringify({ mappings: mockIndexMappingResponseForSemanticText }, null, 2) - ); - }); it('there is a callout with error message when save mappings fail', async () => { const error = { statusCode: 400, @@ -685,6 +645,116 @@ describe('', () => { await testBed.actions.mappings.clickSaveMappingsButton(); expect(testBed.actions.mappings.isSaveMappingsErrorDisplayed()).toBe(true); }); + describe('Add Semantic text field', () => { + const customInferenceModel = 'my-elser-model'; + beforeEach(async () => { + httpRequestsMockHelpers.setInferenceModels({ + data: [ + { + model_id: customInferenceModel, + task_type: 'sparse_embedding', + service: 'elser', + service_settings: { + num_allocations: 1, + num_threads: 1, + model_id: '.elser_model_2', + }, + task_settings: {}, + }, + ], + }); + await act(async () => { + testBed = await setup({ + httpSetup, + dependencies: { + config: { enableSemanticText: true }, + docLinks: { + links: { + ml: '', + enterpriseSearch: '', + }, + }, + plugins: { + ml: { + mlApi: { + trainedModels: { + getTrainedModels: jest.fn().mockResolvedValue([ + { + model_id: '.elser_model_2', + model_type: 'pytorch', + model_package: { + packaged_model_id: customInferenceModel, + model_repository: 'https://ml-models.elastic.co', + minimum_version: '11.0.0', + size: 438123914, + sha256: '', + metadata: {}, + tags: [], + vocabulary_file: 'elser_model_2.vocab.json', + }, + description: 'Elastic Learned Sparse EncodeR v2', + tags: ['elastic'], + }, + ]), + getTrainedModelStats: jest.fn().mockResolvedValue({ + count: 1, + trained_model_stats: [ + { + model_id: '.elser_model_2', + + deployment_stats: { + deployment_id: customInferenceModel, + model_id: '.elser_model_2', + threads_per_allocation: 1, + number_of_allocations: 1, + queue_capacity: 1024, + state: 'started', + }, + }, + { + model_id: '.elser_model_2', + + deployment_stats: { + deployment_id: '.elser_model_2', + model_id: '.elser_model_2', + threads_per_allocation: 1, + number_of_allocations: 1, + queue_capacity: 1024, + state: 'started', + }, + }, + ], + }), + }, + }, + }, + }, + }, + }); + }); + testBed.component.update(); + await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Mappings); + await testBed.actions.mappings.clickAddFieldButton(); + }); + it('can select semantic_text field', async () => { + await testBed.actions.mappings.selectSemanticTextField( + 'semantic_text_name', + 'Semantic text' + ); + + testBed.actions.mappings.isReferenceFieldVisible(); + testBed.actions.mappings.selectInferenceIdButtonExists(); + testBed.actions.mappings.openSelectInferencePopover(); + testBed.actions.mappings.expectDefaultInferenceModelToExists(); + testBed.actions.mappings.expectCustomInferenceModelToExists( + `custom-inference_${customInferenceModel}` + ); + + // can cancel new field + expect(testBed.exists('cancelButton')).toBe(true); + testBed.find('cancelButton').simulate('click'); + }); + }); }); describe('error loading mappings', () => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/select_inference_id.test.tsx similarity index 80% rename from x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.test.tsx rename to x-pack/plugins/index_management/__jest__/client_integration/index_details_page/select_inference_id.test.tsx index 4222cf493a9bf9..c734943ec45920 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/select_inference_id.test.tsx @@ -7,13 +7,13 @@ import { registerTestBed } from '@kbn/test-jest-helpers'; import { act } from 'react-dom/test-utils'; -import { SelectInferenceId } from './select_inference_id'; +import { SelectInferenceId } from '../../../public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id'; const onChangeMock = jest.fn(); const setValueMock = jest.fn(); const setNewInferenceEndpointMock = jest.fn(); -jest.mock('../../../../../app_context', () => ({ +jest.mock('../../../public/application/app_context', () => ({ useAppContext: jest.fn().mockReturnValue({ core: { application: {} }, docLinks: {}, @@ -30,6 +30,17 @@ jest.mock('../../../../../app_context', () => ({ }), })); +jest.mock( + '../../../public/application/components/component_templates/component_templates_context', + () => ({ + useComponentTemplatesContext: jest.fn().mockReturnValue({ + toasts: { + addError: jest.fn(), + addSuccess: jest.fn(), + }, + }), + }) +); describe('SelectInferenceId', () => { let exists: any; let find: any; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/reference_field_selects.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/reference_field_selects.tsx index e8b939ab81f5da..b8f5e866b68a9d 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/reference_field_selects.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/reference_field_selects.tsx @@ -32,7 +32,11 @@ export const ReferenceFieldSelects = ({ Object.keys(data.mappings.properties).forEach((key) => { const field = data.mappings.properties[key]; if (field.type === 'text') { - referenceFieldOptions.push({ value: key, inputDisplay: key }); + referenceFieldOptions.push({ + value: key, + inputDisplay: key, + 'data-test-subj': `select-reference-field-${key}`, + }); } }); } @@ -47,14 +51,15 @@ export const ReferenceFieldSelects = ({ return subscription.unsubscribe; }, [subscribe, onChange]); - return ( -
+
{(field) => ( )} diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx index 1d09c2469c1649..24b99ef9e7c08c 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx @@ -35,28 +35,40 @@ import { ModelConfig, Service, } from '@kbn/inference_integration_flyout/types'; -import { FormattedMessage } from '@kbn/i18n-react'; import { InferenceFlyoutWrapper } from '@kbn/inference_integration_flyout/components/inference_flyout_wrapper'; import { TrainedModelConfigResponse } from '@kbn/ml-plugin/common/types/trained_models'; -import { extractErrorProperties } from '@kbn/ml-error-utils'; import { getFieldConfig } from '../../../lib'; import { useAppContext } from '../../../../../app_context'; import { Form, UseField, useForm } from '../../../shared_imports'; import { useLoadInferenceModels } from '../../../../../services/api'; import { getTrainedModelStats } from '../../../../../../hooks/use_details_page_mappings_model_management'; import { InferenceToModelIdMap } from '../fields'; +import { useMLModelNotificationToasts } from '../../../../../../hooks/use_ml_model_status_toasts'; +import { + CustomInferenceEndpointConfig, + DefaultInferenceModels, + DeploymentState, +} from '../../../types'; const inferenceServiceTypeElasticsearchModelMap: Record = { elser: ElasticsearchModelDefaultOptions.elser, elasticsearch: ElasticsearchModelDefaultOptions.e5, }; - +const uncheckSelectedModelOption = (options: EuiSelectableOption[]) => { + const checkedOption = options.find(({ checked }) => checked === 'on'); + if (checkedOption) { + checkedOption.checked = undefined; + } +}; interface Props { onChange(value: string): void; 'data-test-subj'?: string; setValue: (value: string) => void; - setNewInferenceEndpoint: (newInferenceEndpoint: InferenceToModelIdMap) => void; + setNewInferenceEndpoint: ( + newInferenceEndpoint: InferenceToModelIdMap, + customInferenceEndpointConfig: CustomInferenceEndpointConfig + ) => void; } export const SelectInferenceId = ({ onChange, @@ -76,16 +88,14 @@ export const SelectInferenceId = ({ }); }, [ml]); - const { form } = useForm({ defaultValue: { main: 'elser_model_2' } }); + const { form } = useForm({ defaultValue: { main: DefaultInferenceModels.elser_model_2 } }); const { subscribe } = form; const [isInferenceFlyoutVisible, setIsInferenceFlyoutVisible] = useState(false); - const [inferenceAddError, setInferenceAddError] = useState(undefined); const [availableTrainedModels, setAvailableTrainedModels] = useState< TrainedModelConfigResponse[] >([]); const onFlyoutClose = useCallback(() => { - setInferenceAddError(undefined); setIsInferenceFlyoutVisible(!isInferenceFlyoutVisible); }, [isInferenceFlyoutVisible]); useEffect(() => { @@ -111,16 +121,27 @@ export const SelectInferenceId = ({ const fieldConfigModelId = getFieldConfig('inference_id'); const defaultInferenceIds: EuiSelectableOption[] = useMemo(() => { - return [{ checked: 'on', label: 'elser_model_2' }, { label: 'e5' }]; + return [ + { + checked: 'on', + label: 'elser_model_2', + 'data-test-subj': 'default-inference_elser_model_2', + }, + { + label: 'e5', + 'data-test-subj': 'default-inference_e5', + }, + ]; }, []); - const { isLoading, data: models, resendRequest } = useLoadInferenceModels(); + const { isLoading, data: models } = useLoadInferenceModels(); const [options, setOptions] = useState([...defaultInferenceIds]); const inferenceIdOptionsFromModels = useMemo(() => { const inferenceIdOptions = models?.map((model: InferenceAPIConfigResponse) => ({ label: model.model_id, + 'data-test-subj': `custom-inference_${model.model_id}`, })) || []; return inferenceIdOptions; @@ -136,40 +157,48 @@ export const SelectInferenceId = ({ }; setOptions(Object.values(mergedOptions)); }, [inferenceIdOptionsFromModels, defaultInferenceIds]); - const [isCreateInferenceApiLoading, setIsCreateInferenceApiLoading] = useState(false); + + const { showErrorToasts } = useMLModelNotificationToasts(); const onSaveInferenceCallback = useCallback( async (inferenceId: string, taskType: InferenceTaskType, modelConfig: ModelConfig) => { - setIsCreateInferenceApiLoading(true); + setIsInferenceFlyoutVisible(!isInferenceFlyoutVisible); try { - await ml?.mlApi?.inferenceModels?.createInferenceEndpoint( - inferenceId, - taskType, - modelConfig - ); - setIsInferenceFlyoutVisible(!isInferenceFlyoutVisible); - setIsCreateInferenceApiLoading(false); - setInferenceAddError(undefined); + const isDeployable = + modelConfig.service === Service.elser || modelConfig.service === Service.elasticsearch; + + const newOption: EuiSelectableOption[] = [ + { + label: inferenceId, + checked: 'on', + 'data-test-subj': `custom-inference_${inferenceId}`, + }, + ]; + // uncheck selected endpoint id + uncheckSelectedModelOption(options); + + setOptions([...options, ...newOption]); + const trainedModelStats = await ml?.mlApi?.trainedModels.getTrainedModelStats(); const defaultEndpointId = inferenceServiceTypeElasticsearchModelMap[modelConfig.service] || ''; const newModelId: InferenceToModelIdMap = {}; newModelId[inferenceId] = { trainedModelId: defaultEndpointId, - isDeployable: - modelConfig.service === Service.elser || modelConfig.service === Service.elasticsearch, - isDeployed: getTrainedModelStats(trainedModelStats)[defaultEndpointId] === 'deployed', - defaultInferenceEndpoint: false, + isDeployable, + isDeployed: + getTrainedModelStats(trainedModelStats)[defaultEndpointId] === DeploymentState.DEPLOYED, + }; + const customInferenceEndpointConfig: CustomInferenceEndpointConfig = { + taskType, + modelConfig, }; - resendRequest(); - setNewInferenceEndpoint(newModelId); + setNewInferenceEndpoint(newModelId, customInferenceEndpointConfig); } catch (error) { - const errorObj = extractErrorProperties(error); - setInferenceAddError(errorObj.message); - setIsCreateInferenceApiLoading(false); + showErrorToasts(error); } }, - [isInferenceFlyoutVisible, resendRequest, ml, setNewInferenceEndpoint] + [isInferenceFlyoutVisible, ml, setNewInferenceEndpoint, options, showErrorToasts] ); useEffect(() => { const subscription = subscribe((updateData) => { @@ -182,7 +211,7 @@ export const SelectInferenceId = ({ }, [subscribe, onChange]); const selectedOptionLabel = options.find((option) => option.checked)?.label; useEffect(() => { - setValue(selectedOptionLabel ?? 'elser_model_2'); + setValue(selectedOptionLabel ?? DefaultInferenceModels.elser_model_2); }, [selectedOptionLabel, setValue]); const [isInferencePopoverVisible, setIsInferencePopoverVisible] = useState(false); const [inferenceEndpointError, setInferenceEndpointError] = useState( @@ -304,7 +333,7 @@ export const SelectInferenceId = ({ data-test-subj={dataTestSubj} searchable isLoading={isLoading} - singleSelection + singleSelection="always" searchProps={{ compressed: true, placeholder: i18n.translate( @@ -340,32 +369,6 @@ export const SelectInferenceId = ({ - - - - - - - - ) - } onInferenceEndpointChange={onInferenceEndpointChange} inferenceEndpointError={inferenceEndpointError} trainedModels={trainedModels} @@ -374,7 +377,6 @@ export const SelectInferenceId = ({ isInferenceFlyoutVisible={isInferenceFlyoutVisible} supportedNlpModels={docLinks.links.enterpriseSearch.supportedNlpModels} nlpImportModel={docLinks.links.ml.nlpImportModel} - isCreateInferenceApiLoading={isCreateInferenceApiLoading} setInferenceEndpointError={setInferenceEndpointError} /> )} diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx index f91be7bf55fe24..4a3f600753dd42 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/create_field.tsx @@ -14,14 +14,20 @@ import { EuiSpacer, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { ElasticsearchModelDefaultOptions } from '@kbn/inference_integration_flyout/types'; import { MlPluginStart } from '@kbn/ml-plugin/public'; import classNames from 'classnames'; -import React, { useCallback, useEffect } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { EUI_SIZE, TYPE_DEFINITION } from '../../../../constants'; import { fieldSerializer } from '../../../../lib'; import { useDispatch, useMappingsState } from '../../../../mappings_state_context'; import { Form, FormDataProvider, UseField, useForm, useFormData } from '../../../../shared_imports'; -import { Field, MainType, NormalizedFields } from '../../../../types'; +import { + CustomInferenceEndpointConfig, + Field, + MainType, + NormalizedFields, +} from '../../../../types'; import { NameParameter, SubTypeParameter, TypeParameter } from '../../field_parameters'; import { ReferenceFieldSelects } from '../../field_parameters/reference_field_selects'; import { SelectInferenceId } from '../../field_parameters/select_inference_id'; @@ -32,10 +38,9 @@ import { useSemanticText } from './semantic_text/use_semantic_text'; const formWrapper = (props: any) =>
; export interface InferenceToModelIdMap { [key: string]: { - trainedModelId?: string; + trainedModelId: ElasticsearchModelDefaultOptions | string; isDeployed: boolean; isDeployable: boolean; - defaultInferenceEndpoint: boolean; }; } @@ -88,7 +93,9 @@ export const CreateField = React.memo(function CreateFieldComponent({ return subscription.unsubscribe; }, [dispatch, subscribe]); - + const [customInferenceEndpointConfig, setCustomInferenceEndpointConfig] = useState< + CustomInferenceEndpointConfig | undefined + >(undefined); const cancel = () => { if (isAddingFields && onCancelAddingNewFields) { onCancelAddingNewFields(); @@ -125,7 +132,7 @@ export const CreateField = React.memo(function CreateFieldComponent({ form.reset(); if (data.type === 'semantic_text' && !clickOutside) { - handleSemanticText(data); + handleSemanticText(data, customInferenceEndpointConfig); } else { dispatch({ type: 'field.add', value: data }); } @@ -283,7 +290,10 @@ export const CreateField = React.memo(function CreateFieldComponent({ }} {/* Field inference_id for semantic_text field type */} - + {renderFormActions()} @@ -311,16 +321,20 @@ function ReferenceFieldCombo({ indexName }: { indexName?: string }) { interface InferenceProps { setValue: (value: string) => void; + setCustomInferenceEndpointConfig: (config: CustomInferenceEndpointConfig) => void; } -function InferenceIdCombo({ setValue }: InferenceProps) { +function InferenceIdCombo({ setValue, setCustomInferenceEndpointConfig }: InferenceProps) { const { inferenceToModelIdMap } = useMappingsState(); const dispatch = useDispatch(); const [{ type }] = useFormData({ watch: 'type' }); // update new inferenceEndpoint const setNewInferenceEndpoint = useCallback( - (newInferenceEndpoint: InferenceToModelIdMap) => { + ( + newInferenceEndpoint: InferenceToModelIdMap, + customInferenceEndpointConfig: CustomInferenceEndpointConfig + ) => { dispatch({ type: 'inferenceToModelIdMap.update', value: { @@ -330,8 +344,9 @@ function InferenceIdCombo({ setValue }: InferenceProps) { }, }, }); + setCustomInferenceEndpointConfig(customInferenceEndpointConfig); }, - [dispatch, inferenceToModelIdMap] + [dispatch, inferenceToModelIdMap, setCustomInferenceEndpointConfig] ); if (type === undefined || type[0]?.value !== 'semantic_text') { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.test.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.test.ts index 062c0b93c303e4..4833562e58e31c 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.test.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.test.ts @@ -6,7 +6,7 @@ */ import { renderHook } from '@testing-library/react-hooks'; -import { Field } from '../../../../../types'; +import { CustomInferenceEndpointConfig, Field } from '../../../../../types'; import { useSemanticText } from './use_semantic_text'; import { act } from 'react-dom/test-utils'; @@ -15,22 +15,54 @@ const mlMock: any = { inferenceModels: { createInferenceEndpoint: jest.fn().mockResolvedValue({}), }, - trainedModels: { - startModelAllocation: jest.fn().mockResolvedValue({}), - getTrainedModels: jest.fn().mockResolvedValue([ - { - fully_defined: true, - }, - ]), - }, }, }; -const mockFieldData = { - name: 'name', - type: 'semantic_text', - inferenceId: 'elser_model_2', -} as Field; +const mockField: Record = { + elser_model_2: { + name: 'name', + type: 'semantic_text', + inferenceId: 'elser_model_2', + }, + e5: { + name: 'name', + type: 'semantic_text', + inferenceId: 'e5', + }, + openai: { + name: 'name', + type: 'semantic_text', + inferenceId: 'openai', + }, + my_elser_endpoint: { + name: 'name', + type: 'semantic_text', + inferenceId: 'my_elser_endpoint', + }, +}; + +const mockConfig: Record = { + openai: { + taskType: 'text_embedding', + modelConfig: { + service: 'openai', + service_settings: { + api_key: 'test', + model_id: 'text-embedding-ada-002', + }, + }, + }, + elser: { + taskType: 'sparse_embedding', + modelConfig: { + service: 'elser', + service_settings: { + num_allocations: 1, + num_threads: 1, + }, + }, + }, +}; const mockDispatch = jest.fn(); @@ -38,13 +70,21 @@ jest.mock('../../../../../mappings_state_context', () => ({ useMappingsState: jest.fn().mockReturnValue({ inferenceToModelIdMap: { e5: { - defaultInferenceEndpoint: false, isDeployed: false, isDeployable: true, trainedModelId: '.multilingual-e5-small', }, elser_model_2: { - defaultInferenceEndpoint: true, + isDeployed: false, + isDeployable: true, + trainedModelId: '.elser_model_2', + }, + openai: { + isDeployed: false, + isDeployable: false, + trainedModelId: '', + }, + my_elser_endpoint: { isDeployed: false, isDeployable: true, trainedModelId: '.elser_model_2', @@ -63,24 +103,108 @@ jest.mock('../../../../../../component_templates/component_templates_context', ( }), })); +jest.mock('../../../../../../../services/api', () => ({ + getInferenceModels: jest.fn().mockResolvedValue({ + data: [ + { + model_id: 'e5', + task_type: 'text_embedding', + service: 'elasticsearch', + service_settings: { + num_allocations: 1, + num_threads: 1, + model_id: '.multilingual-e5-small', + }, + task_settings: {}, + }, + ], + }), +})); + describe('useSemanticText', () => { - let form: any; + let mockForm: any; beforeEach(() => { jest.clearAllMocks(); - form = { - getFields: jest.fn().mockReturnValue({ - referenceField: { value: 'title' }, - name: { value: 'sem' }, - type: { value: [{ value: 'semantic_text' }] }, - inferenceId: { value: 'e5' }, - }), + mockForm = { + form: { + getFields: jest.fn().mockReturnValue({ + referenceField: { value: 'title' }, + name: { value: 'sem' }, + type: { value: [{ value: 'semantic_text' }] }, + inferenceId: { value: 'e5' }, + }), + }, + thirdPartyModel: { + getFields: jest.fn().mockReturnValue({ + referenceField: { value: 'title' }, + name: { value: 'semantic_text_openai_endpoint' }, + type: { value: [{ value: 'semantic_text' }] }, + inferenceId: { value: 'openai' }, + }), + }, + elasticModelEndpointCreatedfromFlyout: { + getFields: jest.fn().mockReturnValue({ + referenceField: { value: 'title' }, + name: { value: 'semantic_text_elserServiceType_endpoint' }, + type: { value: [{ value: 'semantic_text' }] }, + inferenceId: { value: 'my_elser_endpoint' }, + }), + }, }; }); + it('should handle semantic text with third party model correctly', async () => { + const { result } = renderHook(() => + useSemanticText({ + form: mockForm.thirdPartyModel, + setErrorsInTrainedModelDeployment: jest.fn(), + ml: mlMock, + }) + ); + await act(async () => { + result.current.setInferenceValue('openai'); + result.current.handleSemanticText(mockField.openai, mockConfig.openai); + }); + expect(mockDispatch).toHaveBeenCalledWith({ + type: 'field.addSemanticText', + value: mockField.openai, + }); + expect(mlMock.mlApi.inferenceModels.createInferenceEndpoint).toHaveBeenCalledWith( + 'openai', + 'text_embedding', + mockConfig.openai.modelConfig + ); + }); + it('should handle semantic text with inference endpoint created from flyout correctly', async () => { + const { result } = renderHook(() => + useSemanticText({ + form: mockForm.elasticModelEndpointCreatedfromFlyout, + setErrorsInTrainedModelDeployment: jest.fn(), + ml: mlMock, + }) + ); + await act(async () => { + result.current.setInferenceValue('my_elser_endpoint'); + result.current.handleSemanticText(mockField.my_elser_endpoint, mockConfig.elser); + }); + expect(mockDispatch).toHaveBeenCalledWith({ + type: 'field.addSemanticText', + value: mockField.my_elser_endpoint, + }); + expect(mlMock.mlApi.inferenceModels.createInferenceEndpoint).toHaveBeenCalledWith( + 'my_elser_endpoint', + 'sparse_embedding', + mockConfig.elser.modelConfig + ); + }); it('should populate the values from the form', () => { const { result } = renderHook(() => - useSemanticText({ form, setErrorsInTrainedModelDeployment: jest.fn(), ml: mlMock }) + useSemanticText({ + form: mockForm.form, + setErrorsInTrainedModelDeployment: jest.fn(), + ml: mlMock, + }) ); expect(result.current.referenceFieldComboValue).toBe('title'); @@ -91,23 +215,26 @@ describe('useSemanticText', () => { it('should handle semantic text correctly', async () => { const { result } = renderHook(() => - useSemanticText({ form, setErrorsInTrainedModelDeployment: jest.fn(), ml: mlMock }) + useSemanticText({ + form: mockForm.form, + setErrorsInTrainedModelDeployment: jest.fn(), + ml: mlMock, + }) ); await act(async () => { - result.current.handleSemanticText(mockFieldData); + result.current.handleSemanticText(mockField.elser_model_2); }); - expect(mlMock.mlApi.trainedModels.startModelAllocation).toHaveBeenCalledWith('.elser_model_2'); expect(mockDispatch).toHaveBeenCalledWith({ type: 'field.addSemanticText', - value: mockFieldData, + value: mockField.elser_model_2, }); expect(mlMock.mlApi.inferenceModels.createInferenceEndpoint).toHaveBeenCalledWith( 'elser_model_2', - 'text_embedding', + 'sparse_embedding', { - service: 'elasticsearch', + service: 'elser', service_settings: { num_allocations: 1, num_threads: 1, @@ -116,68 +243,42 @@ describe('useSemanticText', () => { } ); }); - - it('should invoke the download api if the model does not exist', async () => { - const mlMockWithModelNotDownloaded: any = { - mlApi: { - inferenceModels: { - createInferenceEndpoint: jest.fn(), - }, - trainedModels: { - startModelAllocation: jest.fn(), - getTrainedModels: jest.fn().mockResolvedValue([ - { - fully_defined: false, - }, - ]), - installElasticTrainedModelConfig: jest.fn().mockResolvedValue({}), - }, - }, - }; + it('does not call create inference endpoint api, if default endpoint already exists', async () => { const { result } = renderHook(() => useSemanticText({ - form, + form: mockForm.form, setErrorsInTrainedModelDeployment: jest.fn(), - ml: mlMockWithModelNotDownloaded, + ml: mlMock, }) ); await act(async () => { - result.current.handleSemanticText(mockFieldData); + result.current.setInferenceValue('e5'); + result.current.handleSemanticText(mockField.e5); }); - expect( - mlMockWithModelNotDownloaded.mlApi.trainedModels.installElasticTrainedModelConfig - ).toHaveBeenCalledWith('.elser_model_2'); - expect( - mlMockWithModelNotDownloaded.mlApi.trainedModels.startModelAllocation - ).toHaveBeenCalledWith('.elser_model_2'); - expect( - mlMockWithModelNotDownloaded.mlApi.inferenceModels.createInferenceEndpoint - ).toHaveBeenCalledWith('elser_model_2', 'text_embedding', { - service: 'elasticsearch', - service_settings: { - num_allocations: 1, - num_threads: 1, - model_id: '.elser_model_2', - }, + expect(mockDispatch).toHaveBeenCalledWith({ + type: 'field.addSemanticText', + value: mockField.e5, }); + + expect(mlMock.mlApi.inferenceModels.createInferenceEndpoint).not.toBeCalled(); }); it('handles errors correctly', async () => { const mockError = new Error('Test error'); - mlMock.mlApi?.trainedModels.startModelAllocation.mockImplementationOnce(() => { + mlMock.mlApi?.inferenceModels.createInferenceEndpoint.mockImplementationOnce(() => { throw mockError; }); const setErrorsInTrainedModelDeployment = jest.fn(); const { result } = renderHook(() => - useSemanticText({ form, setErrorsInTrainedModelDeployment, ml: mlMock }) + useSemanticText({ form: mockForm.form, setErrorsInTrainedModelDeployment, ml: mlMock }) ); await act(async () => { - result.current.handleSemanticText(mockFieldData); + result.current.handleSemanticText(mockField.elser_model_2); }); expect(setErrorsInTrainedModelDeployment).toHaveBeenCalledWith(expect.any(Function)); diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.ts index dda1bfe794c97f..01a37275a54ddd 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.ts @@ -7,30 +7,39 @@ import { i18n } from '@kbn/i18n'; import { useCallback } from 'react'; -import { MlPluginStart, TrainedModelConfigResponse } from '@kbn/ml-plugin/public'; +import { MlPluginStart } from '@kbn/ml-plugin/public'; import React, { useEffect, useState } from 'react'; -import { useComponentTemplatesContext } from '../../../../../../component_templates/component_templates_context'; +import { ElasticsearchModelDefaultOptions } from '@kbn/inference_integration_flyout/types'; +import { InferenceTaskType } from '@elastic/elasticsearch/lib/api/types'; +import { InferenceAPIConfigResponse } from '@kbn/ml-trained-models-utils'; import { useDispatch, useMappingsState } from '../../../../../mappings_state_context'; import { FormHook } from '../../../../../shared_imports'; -import { Field } from '../../../../../types'; +import { CustomInferenceEndpointConfig, DefaultInferenceModels, Field } from '../../../../../types'; +import { useMLModelNotificationToasts } from '../../../../../../../../hooks/use_ml_model_status_toasts'; +import { getInferenceModels } from '../../../../../../../services/api'; interface UseSemanticTextProps { form: FormHook; ml?: MlPluginStart; setErrorsInTrainedModelDeployment: React.Dispatch> | undefined; } +interface DefaultInferenceEndpointConfig { + taskType: InferenceTaskType; + service: string; +} export function useSemanticText(props: UseSemanticTextProps) { const { form, setErrorsInTrainedModelDeployment, ml } = props; const { inferenceToModelIdMap } = useMappingsState(); - const { toasts } = useComponentTemplatesContext(); const dispatch = useDispatch(); - const [referenceFieldComboValue, setReferenceFieldComboValue] = useState(); const [nameValue, setNameValue] = useState(); const [inferenceIdComboValue, setInferenceIdComboValue] = useState(); const [semanticFieldType, setSemanticTextFieldType] = useState(); - const [inferenceValue, setInferenceValue] = useState('elser_model_2'); + const [inferenceValue, setInferenceValue] = useState( + DefaultInferenceModels.elser_model_2 + ); + const { showSuccessToasts, showErrorToasts } = useMLModelNotificationToasts(); const useFieldEffect = ( semanticTextform: FormHook, @@ -65,113 +74,92 @@ export function useSemanticText(props: UseSemanticTextProps) { } }, [form, inferenceId, inferenceToModelIdMap]); - const isModelDownloaded = useCallback( - async (modelId: string) => { + const createInferenceEndpoint = useCallback( + async ( + trainedModelId: ElasticsearchModelDefaultOptions | string, + data: Field, + customInferenceEndpointConfig?: CustomInferenceEndpointConfig + ) => { + if (data.inferenceId === undefined) { + throw new Error( + i18n.translate('xpack.idxMgmt.mappingsEditor.createField.undefinedInferenceIdError', { + defaultMessage: 'InferenceId is undefined while creating the inference endpoint.', + }) + ); + } + const defaultInferenceEndpointConfig: DefaultInferenceEndpointConfig = { + service: + trainedModelId === ElasticsearchModelDefaultOptions.elser ? 'elser' : 'elasticsearch', + taskType: + trainedModelId === ElasticsearchModelDefaultOptions.elser + ? 'sparse_embedding' + : 'text_embedding', + }; + + const modelConfig = customInferenceEndpointConfig + ? customInferenceEndpointConfig.modelConfig + : { + service: defaultInferenceEndpointConfig.service, + service_settings: { + num_allocations: 1, + num_threads: 1, + model_id: trainedModelId, + }, + }; + const taskType: InferenceTaskType = + customInferenceEndpointConfig?.taskType ?? defaultInferenceEndpointConfig.taskType; try { - const response: TrainedModelConfigResponse[] | undefined = - await ml?.mlApi?.trainedModels.getTrainedModels(modelId, { - include: 'definition_status', - }); - return !!response?.[0]?.fully_defined; + await ml?.mlApi?.inferenceModels?.createInferenceEndpoint( + data.inferenceId, + taskType, + modelConfig + ); } catch (error) { - if (error.body.statusCode !== 404) { - throw error; - } + throw error; } - return false; }, - [ml?.mlApi?.trainedModels] + [ml?.mlApi?.inferenceModels] ); - const createInferenceEndpoint = ( - trainedModelId: string, - defaultInferenceEndpoint: boolean, - data: Field + const handleSemanticText = async ( + data: Field, + customInferenceEndpointConfig?: CustomInferenceEndpointConfig ) => { - if (data.inferenceId === undefined) { - throw new Error( - i18n.translate('xpack.idxMgmt.mappingsEditor.createField.undefinedInferenceIdError', { - defaultMessage: 'InferenceId is undefined while creating the inference endpoint.', - }) - ); - } - - if (trainedModelId && defaultInferenceEndpoint) { - const modelConfig = { - service: 'elasticsearch', - service_settings: { - num_allocations: 1, - num_threads: 1, - model_id: trainedModelId, - }, - }; - - ml?.mlApi?.inferenceModels?.createInferenceEndpoint( - data.inferenceId, - 'text_embedding', - modelConfig - ); - } - }; - - const handleSemanticText = async (data: Field) => { data.inferenceId = inferenceValue; if (data.inferenceId === undefined) { return; } - const inferenceData = inferenceToModelIdMap?.[data.inferenceId]; - if (!inferenceData) { return; } - const { trainedModelId, defaultInferenceEndpoint, isDeployed, isDeployable } = inferenceData; + const { trainedModelId } = inferenceData; + dispatch({ type: 'field.addSemanticText', value: data }); - if (isDeployable && trainedModelId) { - try { - const modelDownloaded: boolean = await isModelDownloaded(trainedModelId); + try { + // if model exists already, do not create inference endpoint + const inferenceModels = await getInferenceModels(); + const inferenceModel: InferenceAPIConfigResponse[] = inferenceModels.data.some( + (e: InferenceAPIConfigResponse) => e.model_id === inferenceValue + ); + if (inferenceModel) { + return; + } - if (isDeployed) { - createInferenceEndpoint(trainedModelId, defaultInferenceEndpoint, data); - } else if (modelDownloaded) { - ml?.mlApi?.trainedModels - .startModelAllocation(trainedModelId) - .then(() => createInferenceEndpoint(trainedModelId, defaultInferenceEndpoint, data)); - } else { - ml?.mlApi?.trainedModels - .installElasticTrainedModelConfig(trainedModelId) - .then(() => ml?.mlApi?.trainedModels.startModelAllocation(trainedModelId)) - .then(() => createInferenceEndpoint(trainedModelId, defaultInferenceEndpoint, data)); - } - toasts?.addSuccess({ - title: i18n.translate( - 'xpack.idxMgmt.mappingsEditor.createField.modelDeploymentStartedNotification', - { - defaultMessage: 'Model deployment started', - } - ), - text: i18n.translate( - 'xpack.idxMgmt.mappingsEditor.createField.modelDeploymentNotification', - { - defaultMessage: '1 model is being deployed on your ml_node.', - } - ), - }); - } catch (error) { + if (trainedModelId) { + // show toasts only if it's elastic models + showSuccessToasts(); + } + + await createInferenceEndpoint(trainedModelId, data, customInferenceEndpointConfig); + } catch (error) { + // trainedModelId is empty string when it's a third party model + if (trainedModelId) { setErrorsInTrainedModelDeployment?.((prevItems) => [...prevItems, trainedModelId]); - toasts?.addError(error.body && error.body.message ? new Error(error.body.message) : error, { - title: i18n.translate( - 'xpack.idxMgmt.mappingsEditor.createField.modelDeploymentErrorTitle', - { - defaultMessage: 'Model deployment failed', - } - ), - }); } + showErrorToasts(error); } - - dispatch({ type: 'field.addSemanticText', value: data }); }; return { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/field_options.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/field_options.tsx index ec6b3e9cabd341..0fc2e49d0a9cfe 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/field_options.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/field_options.tsx @@ -26,6 +26,7 @@ export const FIELD_TYPES_OPTIONS = Object.entries(MAIN_DATA_TYPE_DEFINITION).map ([dataType, { label }]) => ({ value: dataType, label, + 'data-test-subj': `fieldTypesOptions-${dataType}`, }) ) as ComboBoxOption[]; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/types/document_fields.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/types/document_fields.ts index 53f553f8659ad5..767d29aaaeda82 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/types/document_fields.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/types/document_fields.ts @@ -7,6 +7,8 @@ import { ReactNode } from 'react'; +import { InferenceTaskType } from '@elastic/elasticsearch/lib/api/types'; +import { ModelConfig } from '@kbn/inference_integration_flyout'; import { GenericObject } from './mappings_editor'; import { PARAMETERS_DEFINITION } from '../constants'; @@ -246,3 +248,16 @@ export interface NormalizedRuntimeField { export interface NormalizedRuntimeFields { [id: string]: NormalizedRuntimeField; } +export enum DefaultInferenceModels { + elser_model_2 = 'elser_model_2', + e5 = 'e5', +} + +export enum DeploymentState { + 'DEPLOYED' = 'deployed', + 'NOT_DEPLOYED' = 'not_deployed', +} +export interface CustomInferenceEndpointConfig { + taskType: InferenceTaskType; + modelConfig: ModelConfig; +} diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/trained_models_deployment_modal.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/trained_models_deployment_modal.tsx index 4521a64c1dac4d..8c2bfbbbef96d0 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/trained_models_deployment_modal.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/trained_models_deployment_modal.tsx @@ -84,9 +84,9 @@ export function TrainedModelsDeploymentModal({ onCancel={closeModal} onConfirm={refreshModal} cancelButtonText={i18n.translate( - 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.cancelButtonLabel', + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.closeButtonLabel', { - defaultMessage: 'Cancel', + defaultMessage: 'Close', } )} confirmButtonText={i18n.translate( diff --git a/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.test.ts b/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.test.ts index 98ecbb23b989a4..1517b9664f3ea4 100644 --- a/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.test.ts +++ b/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.test.ts @@ -104,13 +104,11 @@ const inferenceToModelIdMap = { trainedModelId: '.elser_model_2', isDeployed: true, isDeployable: true, - defaultInferenceEndpoint: false, }, e5: { trainedModelId: '.multilingual-e5-small', isDeployed: true, isDeployable: true, - defaultInferenceEndpoint: false, }, } as InferenceToModelIdMap; @@ -127,13 +125,11 @@ describe('useDetailsPageMappingsModelManagement', () => { value: { inferenceToModelIdMap: { e5: { - defaultInferenceEndpoint: false, isDeployed: false, isDeployable: true, trainedModelId: '.multilingual-e5-small', }, elser_model_2: { - defaultInferenceEndpoint: true, isDeployed: true, isDeployable: true, trainedModelId: '.elser_model_2', diff --git a/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.ts b/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.ts index fb27053d35547b..38cf20b9bf534c 100644 --- a/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.ts +++ b/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.ts @@ -13,14 +13,18 @@ import { useAppContext } from '../application/app_context'; import { InferenceToModelIdMap } from '../application/components/mappings_editor/components/document_fields/fields'; import { deNormalize } from '../application/components/mappings_editor/lib'; import { useDispatch } from '../application/components/mappings_editor/mappings_state_context'; -import { NormalizedFields } from '../application/components/mappings_editor/types'; +import { + DefaultInferenceModels, + DeploymentState, + NormalizedFields, +} from '../application/components/mappings_editor/types'; import { getInferenceModels } from '../application/services/api'; interface InferenceModel { data: InferenceAPIConfigResponse[]; } -type DeploymentStatusType = Record; +type DeploymentStatusType = Record; const getCustomInferenceIdMap = ( deploymentStatsByModelId: DeploymentStatusType, @@ -39,7 +43,6 @@ const getCustomInferenceIdMap = ( trainedModelId, isDeployable: model.service === Service.elser || model.service === Service.elasticsearch, isDeployed: deploymentStatsByModelId[trainedModelId] === 'deployed', - defaultInferenceEndpoint: false, }; return inferenceMap; }, {}); @@ -50,7 +53,9 @@ export const getTrainedModelStats = (modelStats?: InferenceStatsResponse): Deplo modelStats?.trained_model_stats.reduce((acc, modelStat) => { if (modelStat.model_id) { acc[modelStat.model_id] = - modelStat?.deployment_stats?.state === 'started' ? 'deployed' : 'not_deployed'; + modelStat?.deployment_stats?.state === 'started' + ? DeploymentState.DEPLOYED + : DeploymentState.NOT_DEPLOYED; } return acc; }, {}) || {} @@ -59,17 +64,18 @@ export const getTrainedModelStats = (modelStats?: InferenceStatsResponse): Deplo const getDefaultInferenceIds = (deploymentStatsByModelId: DeploymentStatusType) => { return { - elser_model_2: { - trainedModelId: '.elser_model_2', + [DefaultInferenceModels.elser_model_2]: { + trainedModelId: ElasticsearchModelDefaultOptions.elser, isDeployable: true, - isDeployed: deploymentStatsByModelId['.elser_model_2'] === 'deployed', - defaultInferenceEndpoint: true, + isDeployed: + deploymentStatsByModelId[ElasticsearchModelDefaultOptions.elser] === + DeploymentState.DEPLOYED, }, - e5: { - trainedModelId: '.multilingual-e5-small', + [DefaultInferenceModels.e5]: { + trainedModelId: ElasticsearchModelDefaultOptions.e5, isDeployable: true, - isDeployed: deploymentStatsByModelId['.multilingual-e5-small'] === 'deployed', - defaultInferenceEndpoint: true, + isDeployed: + deploymentStatsByModelId[ElasticsearchModelDefaultOptions.e5] === DeploymentState.DEPLOYED, }, }; }; diff --git a/x-pack/plugins/index_management/public/hooks/use_ml_model_status_toasts.ts b/x-pack/plugins/index_management/public/hooks/use_ml_model_status_toasts.ts new file mode 100644 index 00000000000000..c9a0c37a37fc91 --- /dev/null +++ b/x-pack/plugins/index_management/public/hooks/use_ml_model_status_toasts.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 { i18n } from '@kbn/i18n'; +import { ErrorType, extractErrorProperties, MLRequestFailure } from '@kbn/ml-error-utils'; +import { useComponentTemplatesContext } from '../application/components/component_templates/component_templates_context'; + +export function useMLModelNotificationToasts() { + const { toasts } = useComponentTemplatesContext(); + const showSuccessToasts = () => { + return toasts.addSuccess({ + title: i18n.translate( + 'xpack.idxMgmt.mappingsEditor.createField.modelDeploymentStartedNotification', + { + defaultMessage: 'Model deployment started', + } + ), + text: i18n.translate('xpack.idxMgmt.mappingsEditor.createField.modelDeploymentNotification', { + defaultMessage: '1 model is being deployed on your ml_node.', + }), + }); + }; + const showErrorToasts = (error: ErrorType) => { + const errorObj = extractErrorProperties(error); + return toasts.addError(new MLRequestFailure(errorObj, error), { + title: i18n.translate('xpack.idxMgmt.mappingsEditor.createField.modelDeploymentErrorTitle', { + defaultMessage: 'Model deployment failed', + }), + }); + }; + return { showSuccessToasts, showErrorToasts }; +} diff --git a/x-pack/plugins/index_management/tsconfig.json b/x-pack/plugins/index_management/tsconfig.json index 202a755a8b21de..ec199f7b11f535 100644 --- a/x-pack/plugins/index_management/tsconfig.json +++ b/x-pack/plugins/index_management/tsconfig.json @@ -49,9 +49,9 @@ "@kbn/utility-types", "@kbn/inference_integration_flyout", "@kbn/ml-plugin", - "@kbn/ml-error-utils", "@kbn/react-kibana-context-render", - "@kbn/react-kibana-mount" + "@kbn/react-kibana-mount", + "@kbn/ml-error-utils", ], "exclude": ["target/**/*"] } From e52750ff1d5e3ab227ffe46421c1439403f6aec4 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 18 Jun 2024 00:02:30 +0200 Subject: [PATCH 006/123] [Discover] Add deprecation badges to some of old Advanced Settings (#185871) - Closes https://github.com/elastic/kibana/issues/179899 ## Summary This PR adds deprecation badges to: - discover:searchFieldsFromSource - doc_table:legacy - rollups:enableIndexPatterns --- packages/kbn-doc-links/src/get_doc_links.ts | 1 + src/plugins/discover/server/ui_settings.ts | 18 ++++++++++++++++++ x-pack/plugins/rollup/server/plugin.ts | 6 ++++++ 3 files changed, 25 insertions(+) diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 00899f64f3d634..3fcd6df837c290 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -516,6 +516,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D : `${ELASTICSEARCH_DOCS}index-mgmt.html`, kibanaSearchSettings: `${KIBANA_DOCS}advanced-options.html#kibana-search-settings`, discoverSettings: `${KIBANA_DOCS}advanced-options.html#kibana-discover-settings`, + rollupSettings: `${KIBANA_DOCS}advanced-options.html#kibana-rollups-settings`, visualizationSettings: `${KIBANA_DOCS}advanced-options.html#kibana-visualization-settings`, timelionSettings: `${KIBANA_DOCS}advanced-options.html#kibana-timelion-settings`, savedObjectsApiList: `${KIBANA_DOCS}saved-objects-api.html#saved-objects-api`, diff --git a/src/plugins/discover/server/ui_settings.ts b/src/plugins/discover/server/ui_settings.ts index fab0d56c0d828e..5e66e1f2252d1b 100644 --- a/src/plugins/discover/server/ui_settings.ts +++ b/src/plugins/discover/server/ui_settings.ts @@ -207,6 +207,15 @@ export const getUiSettings: ( type: METRIC_TYPE.CLICK, name: 'discover:useLegacyDataGrid', }, + deprecation: { + message: i18n.translate( + 'discover.advancedSettings.discover.disableDocumentExplorerDeprecation', + { + defaultMessage: 'This setting is deprecated and will be removed in Kibana 9.0.', + } + ), + docLinksKey: 'discoverSettings', + }, }, [MODIFY_COLUMNS_ON_SWITCH]: { name: i18n.translate('discover.advancedSettings.discover.modifyColumnsOnSwitchTitle', { @@ -236,6 +245,15 @@ export const getUiSettings: ( value: false, category: ['discover'], schema: schema.boolean(), + deprecation: { + message: i18n.translate( + 'discover.advancedSettings.discover.readFieldsFromSourceDeprecation', + { + defaultMessage: 'This setting is deprecated and will be removed in Kibana 9.0.', + } + ), + docLinksKey: 'discoverSettings', + }, }, [SHOW_FIELD_STATISTICS]: { name: i18n.translate('discover.advancedSettings.discover.showFieldStatistics', { diff --git a/x-pack/plugins/rollup/server/plugin.ts b/x-pack/plugins/rollup/server/plugin.ts index ff8ff7e809b136..cd0a6835cd857c 100644 --- a/x-pack/plugins/rollup/server/plugin.ts +++ b/x-pack/plugins/rollup/server/plugin.ts @@ -90,6 +90,12 @@ export class RollupPlugin implements Plugin { category: ['rollups'], schema: schema.boolean(), requiresPageReload: true, + deprecation: { + message: i18n.translate('xpack.rollupJobs.rollupDataViewsDeprecation', { + defaultMessage: 'This setting is deprecated and will be removed in Kibana 9.0.', + }), + docLinksKey: 'rollupSettings', + }, }, }); From f6943060f78cc590c9f94dd505ce6d85b8227e77 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 18 Jun 2024 07:08:09 +0200 Subject: [PATCH 007/123] [api-docs] 2024-06-18 Daily api_docs build (#186349) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/741 --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- .../ai_assistant_management_selection.mdx | 2 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.mdx | 2 +- api_docs/apm.mdx | 2 +- api_docs/apm_data_access.mdx | 2 +- api_docs/asset_manager.mdx | 2 +- api_docs/assets_data_access.mdx | 2 +- api_docs/banners.mdx | 2 +- api_docs/bfetch.mdx | 2 +- api_docs/canvas.mdx | 2 +- api_docs/cases.mdx | 2 +- api_docs/charts.mdx | 2 +- api_docs/cloud.mdx | 2 +- api_docs/cloud_data_migration.mdx | 2 +- api_docs/cloud_defend.mdx | 2 +- api_docs/cloud_experiments.mdx | 2 +- api_docs/cloud_security_posture.mdx | 2 +- api_docs/console.mdx | 2 +- api_docs/content_management.mdx | 2 +- api_docs/controls.mdx | 2 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.mdx | 2 +- api_docs/data_quality.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.mdx | 2 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/dataset_quality.mdx | 2 +- api_docs/deprecations_by_api.mdx | 2 +- api_docs/deprecations_by_plugin.mdx | 4 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/discover_shared.mdx | 2 +- api_docs/ecs_data_quality_dashboard.mdx | 2 +- api_docs/elastic_assistant.mdx | 2 +- api_docs/embeddable.mdx | 2 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.mdx | 2 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/esql_data_grid.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_annotation_listing.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/exploratory_view.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/fields_metadata.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/files.mdx | 2 +- api_docs/files_management.mdx | 2 +- api_docs/fleet.devdocs.json | 34 +++++-- api_docs/fleet.mdx | 4 +- api_docs/global_search.mdx | 2 +- api_docs/guided_onboarding.mdx | 2 +- api_docs/home.mdx | 2 +- api_docs/image_embeddable.mdx | 2 +- api_docs/index_lifecycle_management.mdx | 2 +- api_docs/index_management.mdx | 2 +- api_docs/infra.mdx | 2 +- api_docs/ingest_pipelines.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/integration_assistant.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/investigate.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_actions_types.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_log_pattern_analysis.mdx | 2 +- api_docs/kbn_aiops_log_rate_analysis.mdx | 2 +- .../kbn_alerting_api_integration_helpers.mdx | 2 +- api_docs/kbn_alerting_comparators.mdx | 2 +- api_docs/kbn_alerting_state_types.mdx | 2 +- api_docs/kbn_alerting_types.mdx | 2 +- api_docs/kbn_alerts_as_data_utils.mdx | 2 +- api_docs/kbn_alerts_ui_shared.mdx | 2 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_client.mdx | 2 +- api_docs/kbn_analytics_collection_utils.mdx | 2 +- ..._analytics_shippers_elastic_v3_browser.mdx | 2 +- ...n_analytics_shippers_elastic_v3_common.mdx | 2 +- ...n_analytics_shippers_elastic_v3_server.mdx | 2 +- api_docs/kbn_analytics_shippers_fullstory.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_data_view.mdx | 2 +- api_docs/kbn_apm_synthtrace.mdx | 2 +- api_docs/kbn_apm_synthtrace_client.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_axe_config.mdx | 2 +- api_docs/kbn_bfetch_error.mdx | 2 +- api_docs/kbn_calculate_auto.mdx | 2 +- .../kbn_calculate_width_from_char_count.mdx | 2 +- api_docs/kbn_cases_components.mdx | 2 +- api_docs/kbn_cell_actions.mdx | 2 +- api_docs/kbn_chart_expressions_common.mdx | 2 +- api_docs/kbn_chart_icons.mdx | 2 +- api_docs/kbn_ci_stats_core.mdx | 2 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 2 +- api_docs/kbn_ci_stats_reporter.mdx | 2 +- api_docs/kbn_cli_dev_mode.mdx | 2 +- api_docs/kbn_code_editor.mdx | 2 +- api_docs/kbn_code_editor_mock.mdx | 2 +- api_docs/kbn_code_owners.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.mdx | 2 +- .../kbn_content_management_content_editor.mdx | 2 +- ...tent_management_tabbed_table_list_view.mdx | 2 +- ...kbn_content_management_table_list_view.mdx | 2 +- ...tent_management_table_list_view_common.mdx | 2 +- ...ntent_management_table_list_view_table.mdx | 2 +- api_docs/kbn_content_management_utils.mdx | 2 +- api_docs/kbn_core_analytics_browser.mdx | 2 +- .../kbn_core_analytics_browser_internal.mdx | 2 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 2 +- api_docs/kbn_core_analytics_server.mdx | 2 +- .../kbn_core_analytics_server_internal.mdx | 2 +- api_docs/kbn_core_analytics_server_mocks.mdx | 2 +- api_docs/kbn_core_application_browser.mdx | 2 +- .../kbn_core_application_browser_internal.mdx | 2 +- .../kbn_core_application_browser_mocks.mdx | 2 +- api_docs/kbn_core_application_common.mdx | 2 +- api_docs/kbn_core_apps_browser_internal.mdx | 2 +- api_docs/kbn_core_apps_browser_mocks.mdx | 2 +- api_docs/kbn_core_apps_server_internal.mdx | 2 +- api_docs/kbn_core_base_browser_mocks.mdx | 2 +- api_docs/kbn_core_base_common.mdx | 2 +- api_docs/kbn_core_base_server_internal.mdx | 2 +- api_docs/kbn_core_base_server_mocks.mdx | 2 +- .../kbn_core_capabilities_browser_mocks.mdx | 2 +- api_docs/kbn_core_capabilities_common.mdx | 2 +- api_docs/kbn_core_capabilities_server.mdx | 2 +- .../kbn_core_capabilities_server_mocks.mdx | 2 +- api_docs/kbn_core_chrome_browser.mdx | 2 +- api_docs/kbn_core_chrome_browser_mocks.mdx | 2 +- api_docs/kbn_core_config_server_internal.mdx | 2 +- api_docs/kbn_core_custom_branding_browser.mdx | 2 +- ..._core_custom_branding_browser_internal.mdx | 2 +- ...kbn_core_custom_branding_browser_mocks.mdx | 2 +- api_docs/kbn_core_custom_branding_common.mdx | 2 +- api_docs/kbn_core_custom_branding_server.mdx | 2 +- ...n_core_custom_branding_server_internal.mdx | 2 +- .../kbn_core_custom_branding_server_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_browser.mdx | 2 +- ...kbn_core_deprecations_browser_internal.mdx | 2 +- .../kbn_core_deprecations_browser_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_common.mdx | 2 +- api_docs/kbn_core_deprecations_server.mdx | 2 +- .../kbn_core_deprecations_server_internal.mdx | 2 +- .../kbn_core_deprecations_server_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_browser.mdx | 2 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_server.mdx | 2 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 2 +- ...e_elasticsearch_client_server_internal.mdx | 2 +- ...core_elasticsearch_client_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_server.mdx | 2 +- ...kbn_core_elasticsearch_server_internal.mdx | 2 +- .../kbn_core_elasticsearch_server_mocks.mdx | 2 +- .../kbn_core_environment_server_internal.mdx | 2 +- .../kbn_core_environment_server_mocks.mdx | 2 +- .../kbn_core_execution_context_browser.mdx | 2 +- ...ore_execution_context_browser_internal.mdx | 2 +- ...n_core_execution_context_browser_mocks.mdx | 2 +- .../kbn_core_execution_context_common.mdx | 2 +- .../kbn_core_execution_context_server.mdx | 2 +- ...core_execution_context_server_internal.mdx | 2 +- ...bn_core_execution_context_server_mocks.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser.mdx | 2 +- .../kbn_core_fatal_errors_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_browser.mdx | 2 +- api_docs/kbn_core_http_browser_internal.mdx | 2 +- api_docs/kbn_core_http_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_common.mdx | 2 +- .../kbn_core_http_context_server_mocks.mdx | 2 +- ...re_http_request_handler_context_server.mdx | 2 +- api_docs/kbn_core_http_resources_server.mdx | 2 +- ...bn_core_http_resources_server_internal.mdx | 2 +- .../kbn_core_http_resources_server_mocks.mdx | 2 +- .../kbn_core_http_router_server_internal.mdx | 2 +- .../kbn_core_http_router_server_mocks.mdx | 2 +- api_docs/kbn_core_http_server.mdx | 2 +- api_docs/kbn_core_http_server_internal.mdx | 2 +- api_docs/kbn_core_http_server_mocks.mdx | 2 +- api_docs/kbn_core_i18n_browser.mdx | 2 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 2 +- api_docs/kbn_core_i18n_server.mdx | 2 +- api_docs/kbn_core_i18n_server_internal.mdx | 2 +- api_docs/kbn_core_i18n_server_mocks.mdx | 2 +- ...n_core_injected_metadata_browser_mocks.mdx | 2 +- ...kbn_core_integrations_browser_internal.mdx | 2 +- .../kbn_core_integrations_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_browser.mdx | 2 +- api_docs/kbn_core_lifecycle_browser_mocks.mdx | 2 +- api_docs/kbn_core_lifecycle_server.mdx | 2 +- api_docs/kbn_core_lifecycle_server_mocks.mdx | 2 +- api_docs/kbn_core_logging_browser_mocks.mdx | 2 +- api_docs/kbn_core_logging_common_internal.mdx | 2 +- api_docs/kbn_core_logging_server.mdx | 2 +- api_docs/kbn_core_logging_server_internal.mdx | 2 +- api_docs/kbn_core_logging_server_mocks.mdx | 2 +- ...ore_metrics_collectors_server_internal.mdx | 2 +- ...n_core_metrics_collectors_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_server.mdx | 2 +- api_docs/kbn_core_metrics_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_server_mocks.mdx | 2 +- api_docs/kbn_core_mount_utils_browser.mdx | 2 +- api_docs/kbn_core_node_server.mdx | 2 +- api_docs/kbn_core_node_server_internal.mdx | 2 +- api_docs/kbn_core_node_server_mocks.mdx | 2 +- api_docs/kbn_core_notifications_browser.mdx | 2 +- ...bn_core_notifications_browser_internal.mdx | 2 +- .../kbn_core_notifications_browser_mocks.mdx | 2 +- api_docs/kbn_core_overlays_browser.mdx | 2 +- .../kbn_core_overlays_browser_internal.mdx | 2 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 2 +- api_docs/kbn_core_plugins_browser.mdx | 2 +- api_docs/kbn_core_plugins_browser_mocks.mdx | 2 +- .../kbn_core_plugins_contracts_browser.mdx | 2 +- .../kbn_core_plugins_contracts_server.mdx | 2 +- api_docs/kbn_core_plugins_server.mdx | 2 +- api_docs/kbn_core_plugins_server_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- api_docs/kbn_core_rendering_browser_mocks.mdx | 2 +- .../kbn_core_rendering_server_internal.mdx | 2 +- api_docs/kbn_core_rendering_server_mocks.mdx | 2 +- api_docs/kbn_core_root_server_internal.mdx | 2 +- .../kbn_core_saved_objects_api_browser.mdx | 2 +- .../kbn_core_saved_objects_api_server.mdx | 2 +- ...bn_core_saved_objects_api_server_mocks.mdx | 2 +- ...ore_saved_objects_base_server_internal.mdx | 2 +- ...n_core_saved_objects_base_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_browser.mdx | 2 +- ...bn_core_saved_objects_browser_internal.mdx | 2 +- .../kbn_core_saved_objects_browser_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_common.mdx | 2 +- ..._objects_import_export_server_internal.mdx | 2 +- ...ved_objects_import_export_server_mocks.mdx | 2 +- ...aved_objects_migration_server_internal.mdx | 2 +- ...e_saved_objects_migration_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_server.mdx | 2 +- ...kbn_core_saved_objects_server_internal.mdx | 2 +- .../kbn_core_saved_objects_server_mocks.mdx | 2 +- .../kbn_core_saved_objects_utils_server.mdx | 2 +- api_docs/kbn_core_security_browser.mdx | 2 +- .../kbn_core_security_browser_internal.mdx | 2 +- api_docs/kbn_core_security_browser_mocks.mdx | 2 +- api_docs/kbn_core_security_common.mdx | 2 +- api_docs/kbn_core_security_server.mdx | 2 +- .../kbn_core_security_server_internal.mdx | 2 +- api_docs/kbn_core_security_server_mocks.mdx | 2 +- api_docs/kbn_core_status_common.mdx | 2 +- api_docs/kbn_core_status_common_internal.mdx | 2 +- api_docs/kbn_core_status_server.mdx | 2 +- api_docs/kbn_core_status_server_internal.mdx | 2 +- api_docs/kbn_core_status_server_mocks.mdx | 2 +- ...core_test_helpers_deprecations_getters.mdx | 2 +- ...n_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_test_helpers_kbn_server.mdx | 2 +- .../kbn_core_test_helpers_model_versions.mdx | 2 +- ...n_core_test_helpers_so_type_serializer.mdx | 2 +- api_docs/kbn_core_test_helpers_test_utils.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- .../kbn_core_ui_settings_browser_internal.mdx | 2 +- .../kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_core_ui_settings_server.mdx | 2 +- .../kbn_core_ui_settings_server_internal.mdx | 2 +- .../kbn_core_ui_settings_server_mocks.mdx | 2 +- api_docs/kbn_core_usage_data_server.mdx | 2 +- .../kbn_core_usage_data_server_internal.mdx | 2 +- api_docs/kbn_core_usage_data_server_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_browser.mdx | 2 +- ...kbn_core_user_profile_browser_internal.mdx | 2 +- .../kbn_core_user_profile_browser_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_common.mdx | 2 +- api_docs/kbn_core_user_profile_server.mdx | 2 +- .../kbn_core_user_profile_server_internal.mdx | 2 +- .../kbn_core_user_profile_server_mocks.mdx | 2 +- api_docs/kbn_core_user_settings_server.mdx | 2 +- .../kbn_core_user_settings_server_mocks.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_custom_icons.mdx | 2 +- api_docs/kbn_custom_integrations.mdx | 2 +- api_docs/kbn_cypress_config.mdx | 2 +- api_docs/kbn_data_forge.mdx | 2 +- api_docs/kbn_data_service.mdx | 2 +- api_docs/kbn_data_stream_adapter.mdx | 2 +- api_docs/kbn_data_view_utils.mdx | 2 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_deeplinks_analytics.mdx | 2 +- api_docs/kbn_deeplinks_devtools.mdx | 2 +- api_docs/kbn_deeplinks_fleet.mdx | 2 +- api_docs/kbn_deeplinks_management.mdx | 2 +- api_docs/kbn_deeplinks_ml.mdx | 2 +- api_docs/kbn_deeplinks_observability.mdx | 2 +- api_docs/kbn_deeplinks_search.mdx | 2 +- api_docs/kbn_deeplinks_security.mdx | 2 +- api_docs/kbn_deeplinks_shared.mdx | 2 +- api_docs/kbn_default_nav_analytics.mdx | 2 +- api_docs/kbn_default_nav_devtools.mdx | 2 +- api_docs/kbn_default_nav_management.mdx | 2 +- api_docs/kbn_default_nav_ml.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_discover_utils.mdx | 2 +- api_docs/kbn_doc_links.devdocs.json | 2 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_dom_drag_drop.mdx | 2 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_ecs_data_quality_dashboard.mdx | 2 +- api_docs/kbn_elastic_agent_utils.mdx | 2 +- api_docs/kbn_elastic_assistant.mdx | 2 +- api_docs/kbn_elastic_assistant_common.mdx | 2 +- api_docs/kbn_entities_schema.mdx | 2 +- api_docs/kbn_es.mdx | 2 +- api_docs/kbn_es_archiver.mdx | 2 +- api_docs/kbn_es_errors.mdx | 2 +- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_es_types.mdx | 2 +- api_docs/kbn_eslint_plugin_imports.mdx | 2 +- api_docs/kbn_esql_ast.mdx | 2 +- api_docs/kbn_esql_utils.mdx | 2 +- api_docs/kbn_esql_validation_autocomplete.mdx | 2 +- api_docs/kbn_event_annotation_common.mdx | 2 +- api_docs/kbn_event_annotation_components.mdx | 2 +- api_docs/kbn_expandable_flyout.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_field_utils.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- api_docs/kbn_formatters.mdx | 2 +- .../kbn_ftr_common_functional_services.mdx | 2 +- .../kbn_ftr_common_functional_ui_services.mdx | 2 +- api_docs/kbn_generate.mdx | 2 +- api_docs/kbn_generate_console_definitions.mdx | 2 +- api_docs/kbn_generate_csv.mdx | 2 +- api_docs/kbn_grouping.mdx | 2 +- api_docs/kbn_guided_onboarding.mdx | 2 +- api_docs/kbn_handlebars.mdx | 2 +- api_docs/kbn_hapi_mocks.mdx | 2 +- api_docs/kbn_health_gateway_server.mdx | 2 +- api_docs/kbn_home_sample_data_card.mdx | 2 +- api_docs/kbn_home_sample_data_tab.mdx | 2 +- api_docs/kbn_i18n.mdx | 2 +- api_docs/kbn_i18n_react.mdx | 2 +- api_docs/kbn_import_resolver.mdx | 2 +- api_docs/kbn_index_management.mdx | 2 +- api_docs/kbn_inference_integration_flyout.mdx | 2 +- api_docs/kbn_infra_forge.mdx | 2 +- api_docs/kbn_interpreter.mdx | 2 +- api_docs/kbn_io_ts_utils.mdx | 2 +- api_docs/kbn_ipynb.mdx | 2 +- api_docs/kbn_jest_serializers.mdx | 2 +- api_docs/kbn_journeys.mdx | 2 +- api_docs/kbn_json_ast.mdx | 2 +- api_docs/kbn_kibana_manifest_schema.mdx | 2 +- .../kbn_language_documentation_popover.mdx | 2 +- api_docs/kbn_lens_embeddable_utils.mdx | 2 +- api_docs/kbn_lens_formula_docs.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_content_badge.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_management_cards_navigation.mdx | 2 +- .../kbn_management_settings_application.mdx | 2 +- ...ent_settings_components_field_category.mdx | 2 +- ...gement_settings_components_field_input.mdx | 2 +- ...nagement_settings_components_field_row.mdx | 2 +- ...bn_management_settings_components_form.mdx | 2 +- ...n_management_settings_field_definition.mdx | 2 +- api_docs/kbn_management_settings_ids.mdx | 2 +- ...n_management_settings_section_registry.mdx | 2 +- api_docs/kbn_management_settings_types.mdx | 2 +- .../kbn_management_settings_utilities.mdx | 2 +- api_docs/kbn_management_storybook_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_maps_vector_tile_utils.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_anomaly_utils.mdx | 2 +- api_docs/kbn_ml_cancellable_search.mdx | 2 +- api_docs/kbn_ml_category_validator.mdx | 2 +- api_docs/kbn_ml_chi2test.mdx | 2 +- .../kbn_ml_data_frame_analytics_utils.mdx | 2 +- api_docs/kbn_ml_data_grid.mdx | 2 +- api_docs/kbn_ml_date_picker.mdx | 2 +- api_docs/kbn_ml_date_utils.mdx | 2 +- api_docs/kbn_ml_error_utils.mdx | 2 +- api_docs/kbn_ml_in_memory_table.mdx | 2 +- api_docs/kbn_ml_is_defined.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_kibana_theme.mdx | 2 +- api_docs/kbn_ml_local_storage.mdx | 2 +- api_docs/kbn_ml_nested_property.mdx | 2 +- api_docs/kbn_ml_number_utils.mdx | 2 +- api_docs/kbn_ml_query_utils.mdx | 2 +- api_docs/kbn_ml_random_sampler_utils.mdx | 2 +- api_docs/kbn_ml_route_utils.mdx | 2 +- api_docs/kbn_ml_runtime_field_utils.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_ml_time_buckets.mdx | 2 +- api_docs/kbn_ml_trained_models_utils.mdx | 2 +- api_docs/kbn_ml_ui_actions.mdx | 2 +- api_docs/kbn_ml_url_state.mdx | 2 +- api_docs/kbn_mock_idp_utils.mdx | 2 +- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_object_versioning.mdx | 2 +- api_docs/kbn_observability_alert_details.mdx | 2 +- .../kbn_observability_alerting_test_data.mdx | 2 +- ...ility_get_padded_alert_time_range_util.mdx | 2 +- api_docs/kbn_openapi_bundler.mdx | 2 +- api_docs/kbn_openapi_generator.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- api_docs/kbn_osquery_io_ts_types.mdx | 2 +- api_docs/kbn_panel_loader.mdx | 2 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_check.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_presentation_containers.mdx | 2 +- api_docs/kbn_presentation_publishing.mdx | 2 +- api_docs/kbn_profiling_utils.mdx | 2 +- api_docs/kbn_random_sampling.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_react_hooks.mdx | 2 +- api_docs/kbn_react_kibana_context_common.mdx | 2 +- api_docs/kbn_react_kibana_context_render.mdx | 2 +- api_docs/kbn_react_kibana_context_root.mdx | 2 +- api_docs/kbn_react_kibana_context_styled.mdx | 2 +- api_docs/kbn_react_kibana_context_theme.mdx | 2 +- api_docs/kbn_react_kibana_mount.mdx | 2 +- api_docs/kbn_repo_file_maps.mdx | 2 +- api_docs/kbn_repo_linter.mdx | 2 +- api_docs/kbn_repo_path.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_reporting_common.mdx | 2 +- api_docs/kbn_reporting_csv_share_panel.mdx | 2 +- api_docs/kbn_reporting_export_types_csv.mdx | 2 +- .../kbn_reporting_export_types_csv_common.mdx | 2 +- api_docs/kbn_reporting_export_types_pdf.mdx | 2 +- .../kbn_reporting_export_types_pdf_common.mdx | 2 +- api_docs/kbn_reporting_export_types_png.mdx | 2 +- .../kbn_reporting_export_types_png_common.mdx | 2 +- api_docs/kbn_reporting_mocks_server.mdx | 2 +- api_docs/kbn_reporting_public.mdx | 2 +- api_docs/kbn_reporting_server.mdx | 2 +- api_docs/kbn_resizable_layout.mdx | 2 +- .../kbn_response_ops_feature_flag_service.mdx | 2 +- api_docs/kbn_rison.mdx | 2 +- api_docs/kbn_router_to_openapispec.mdx | 2 +- api_docs/kbn_router_utils.mdx | 2 +- api_docs/kbn_rrule.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- api_docs/kbn_saved_objects_settings.mdx | 2 +- api_docs/kbn_search_api_panels.mdx | 2 +- api_docs/kbn_search_connectors.mdx | 2 +- api_docs/kbn_search_errors.mdx | 2 +- api_docs/kbn_search_index_documents.mdx | 2 +- api_docs/kbn_search_response_warnings.mdx | 2 +- api_docs/kbn_search_types.mdx | 2 +- api_docs/kbn_security_hardening.mdx | 2 +- api_docs/kbn_security_plugin_types_common.mdx | 2 +- api_docs/kbn_security_plugin_types_public.mdx | 2 +- ..._security_plugin_types_server.devdocs.json | 40 ++++----- api_docs/kbn_security_plugin_types_server.mdx | 2 +- api_docs/kbn_security_solution_features.mdx | 2 +- api_docs/kbn_security_solution_navigation.mdx | 2 +- api_docs/kbn_security_solution_side_nav.mdx | 2 +- ...kbn_security_solution_storybook_config.mdx | 2 +- .../kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_data_table.mdx | 2 +- api_docs/kbn_securitysolution_ecs.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- ...ritysolution_exception_list_components.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ..._securitysolution_io_ts_alerting_types.mdx | 2 +- .../kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- .../kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- api_docs/kbn_serverless_common_settings.mdx | 2 +- .../kbn_serverless_observability_settings.mdx | 2 +- api_docs/kbn_serverless_project_switcher.mdx | 2 +- api_docs/kbn_serverless_search_settings.mdx | 2 +- api_docs/kbn_serverless_security_settings.mdx | 2 +- api_docs/kbn_serverless_storybook_config.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- api_docs/kbn_shared_ux_avatar_solution.mdx | 2 +- .../kbn_shared_ux_button_exit_full_screen.mdx | 2 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_chrome_navigation.mdx | 2 +- api_docs/kbn_shared_ux_error_boundary.mdx | 2 +- api_docs/kbn_shared_ux_file_context.mdx | 2 +- api_docs/kbn_shared_ux_file_image.mdx | 2 +- api_docs/kbn_shared_ux_file_image_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_picker.mdx | 2 +- api_docs/kbn_shared_ux_file_types.mdx | 2 +- api_docs/kbn_shared_ux_file_upload.mdx | 2 +- api_docs/kbn_shared_ux_file_util.mdx | 2 +- api_docs/kbn_shared_ux_link_redirect_app.mdx | 2 +- .../kbn_shared_ux_link_redirect_app_mocks.mdx | 2 +- api_docs/kbn_shared_ux_markdown.mdx | 2 +- api_docs/kbn_shared_ux_markdown_mocks.mdx | 2 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 2 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 2 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_template.mdx | 2 +- ...n_shared_ux_page_kibana_template_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data.mdx | 2 +- .../kbn_shared_ux_page_no_data_config.mdx | 2 +- ...bn_shared_ux_page_no_data_config_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_prompt_not_found.mdx | 2 +- api_docs/kbn_shared_ux_router.mdx | 2 +- api_docs/kbn_shared_ux_router_mocks.mdx | 2 +- api_docs/kbn_shared_ux_storybook_config.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_tabbed_modal.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_slo_schema.devdocs.json | 88 ++++++++++--------- api_docs/kbn_slo_schema.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_sort_predicates.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.devdocs.json | 36 +++++++- api_docs/kbn_test.mdx | 4 +- api_docs/kbn_test_eui_helpers.mdx | 2 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_test_subj_selector.mdx | 2 +- api_docs/kbn_text_based_editor.mdx | 2 +- api_docs/kbn_timerange.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_triggers_actions_ui_types.mdx | 2 +- api_docs/kbn_try_in_console.mdx | 2 +- api_docs/kbn_ts_projects.mdx | 2 +- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kbn_ui_actions_browser.mdx | 2 +- api_docs/kbn_ui_shared_deps_src.mdx | 2 +- api_docs/kbn_ui_theme.mdx | 2 +- api_docs/kbn_unified_data_table.mdx | 2 +- api_docs/kbn_unified_doc_viewer.mdx | 2 +- api_docs/kbn_unified_field_list.mdx | 2 +- api_docs/kbn_unsaved_changes_badge.mdx | 2 +- api_docs/kbn_unsaved_changes_prompt.mdx | 2 +- api_docs/kbn_use_tracked_promise.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_visualization_ui_components.mdx | 2 +- api_docs/kbn_visualization_utils.mdx | 2 +- api_docs/kbn_xstate_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kbn_zod_helpers.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.mdx | 2 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/links.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/logs_data_access.mdx | 2 +- api_docs/logs_explorer.mdx | 2 +- api_docs/logs_shared.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/metrics_data_access.mdx | 2 +- api_docs/ml.mdx | 2 +- api_docs/mock_idp_plugin.mdx | 2 +- api_docs/monitoring.mdx | 2 +- api_docs/monitoring_collection.mdx | 2 +- api_docs/navigation.mdx | 2 +- api_docs/newsfeed.mdx | 2 +- api_docs/no_data_page.mdx | 2 +- api_docs/notifications.mdx | 2 +- api_docs/observability.mdx | 2 +- api_docs/observability_a_i_assistant.mdx | 2 +- api_docs/observability_a_i_assistant_app.mdx | 2 +- .../observability_ai_assistant_management.mdx | 2 +- api_docs/observability_logs_explorer.mdx | 2 +- api_docs/observability_onboarding.mdx | 2 +- api_docs/observability_shared.mdx | 2 +- api_docs/osquery.mdx | 2 +- api_docs/painless_lab.mdx | 2 +- api_docs/plugin_directory.mdx | 8 +- api_docs/presentation_panel.mdx | 2 +- api_docs/presentation_util.mdx | 2 +- api_docs/profiling.mdx | 2 +- api_docs/profiling_data_access.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_finder.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/saved_search.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/search_connectors.mdx | 2 +- api_docs/search_inference_endpoints.mdx | 2 +- api_docs/search_notebooks.mdx | 2 +- api_docs/search_playground.mdx | 2 +- api_docs/security.devdocs.json | 40 ++++----- api_docs/security.mdx | 2 +- api_docs/security_solution.mdx | 2 +- api_docs/security_solution_ess.mdx | 2 +- api_docs/security_solution_serverless.mdx | 2 +- api_docs/serverless.mdx | 2 +- api_docs/serverless_observability.mdx | 2 +- api_docs/serverless_search.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.mdx | 2 +- api_docs/slo.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/stack_connectors.mdx | 2 +- api_docs/task_manager.mdx | 2 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/text_based_languages.mdx | 2 +- api_docs/threat_intelligence.mdx | 2 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_doc_viewer.mdx | 2 +- api_docs/unified_histogram.mdx | 2 +- api_docs/unified_search.mdx | 2 +- api_docs/unified_search_autocomplete.mdx | 2 +- api_docs/uptime.mdx | 2 +- api_docs/url_forwarding.mdx | 2 +- api_docs/usage_collection.mdx | 2 +- api_docs/ux.mdx | 2 +- api_docs/vis_default_editor.mdx | 2 +- api_docs/vis_type_gauge.mdx | 2 +- api_docs/vis_type_heatmap.mdx | 2 +- api_docs/vis_type_pie.mdx | 2 +- api_docs/vis_type_table.mdx | 2 +- api_docs/vis_type_timelion.mdx | 2 +- api_docs/vis_type_timeseries.mdx | 2 +- api_docs/vis_type_vega.mdx | 2 +- api_docs/vis_type_vislib.mdx | 2 +- api_docs/vis_type_xy.mdx | 2 +- api_docs/visualizations.mdx | 2 +- 705 files changed, 854 insertions(+), 796 deletions(-) diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index e669f6344efe4f..624022104e4b52 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index e4ce3d3d809f46..779596da4321e7 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/ai_assistant_management_selection.mdx b/api_docs/ai_assistant_management_selection.mdx index ad899d5b30fa75..48d70e70a59824 100644 --- a/api_docs/ai_assistant_management_selection.mdx +++ b/api_docs/ai_assistant_management_selection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiAssistantManagementSelection title: "aiAssistantManagementSelection" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementSelection plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 9fef5c6dbd430f..6589c58e343975 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 5e1523e0a3842c..a158e8daac03af 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index d6b614ee1d7445..aa4431dbb04dad 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index 5fe9a4777bcc74..3e2cc9fefafc04 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index 51ec9eba5b862a..2d1ba34fc9aaa8 100644 --- a/api_docs/asset_manager.mdx +++ b/api_docs/asset_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetManager title: "assetManager" image: https://source.unsplash.com/400x175/?github description: API docs for the assetManager plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetManager'] --- import assetManagerObj from './asset_manager.devdocs.json'; diff --git a/api_docs/assets_data_access.mdx b/api_docs/assets_data_access.mdx index 50feaddd919fb9..3ee0d44d975bd4 100644 --- a/api_docs/assets_data_access.mdx +++ b/api_docs/assets_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetsDataAccess title: "assetsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the assetsDataAccess plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetsDataAccess'] --- import assetsDataAccessObj from './assets_data_access.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 1535f0fdb0549c..fb0a9a20e575cc 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 00bee7c4b9bc54..393d71d9328ced 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index de7aca323a1b1e..7c71ac4bfb55e1 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 0748b61b123c80..c29e6f64f1930a 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index 634b1e16398dc3..ca4066e185d276 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 1b1693299fe3d2..b1e7c01136a03e 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index 36756a7e7d23db..69ff8dc302a537 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index 88223862d4f6d7..79bf2006480fd9 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index df95c8ca9604fb..e540ca3c9d751a 100644 --- a/api_docs/cloud_experiments.mdx +++ b/api_docs/cloud_experiments.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudExperiments title: "cloudExperiments" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudExperiments plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudExperiments'] --- import cloudExperimentsObj from './cloud_experiments.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index d6421a40ce532c..307768caee6aa5 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index 996aa6c999ae80..31535c63a5280b 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index 6d69b349cc2cab..51ec36c9a0e939 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index aac1852d986dba..61fad6567819c5 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index fe8a893b471de9..55e65c72384d83 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index 1a30d17f3db461..dd62d55494171b 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index 61c87fd0e02863..d2b741e32aed65 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index b8539d3b9a8617..b8bd937dbe6c22 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_quality.mdx b/api_docs/data_quality.mdx index 9f7fe6b7fba4e6..4d138efed58aea 100644 --- a/api_docs/data_quality.mdx +++ b/api_docs/data_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataQuality title: "dataQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the dataQuality plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataQuality'] --- import dataQualityObj from './data_quality.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index ea9672a7a2ef78..ff7b36e4871757 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index e49d31bb27213c..066c7271b7b527 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 9658b11938c7b0..296636689811ff 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 14345fff79b2c5..94ebc7428bc257 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 3c47bb01bfdcf9..4cc110a02ed312 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 6d9cc8fbb6606d..23caaad9e7d54a 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index 7555c409869534..f30163d4e24d12 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 8ed0ba095ef181..7f3ddaf93dd5e3 100644 --- a/api_docs/dataset_quality.mdx +++ b/api_docs/dataset_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/datasetQuality title: "datasetQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the datasetQuality plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'datasetQuality'] --- import datasetQualityObj from './dataset_quality.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 2b7977e2526aee..c810331094fbbd 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index e7ee880cdf970e..7f17da6336fadc 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -860,7 +860,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [use_get_logs_discover_link.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/hooks/use_get_logs_discover_link.tsx#:~:text=indexPatternId) | - | | | [agent_policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts#:~:text=mode), [agent_policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts#:~:text=mode), [agent_policy_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/agent_policy_watch.test.ts#:~:text=mode), [agent_policy_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/agent_policy_watch.test.ts#:~:text=mode) | 8.8.0 | | | [agent_policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts#:~:text=mode), [agent_policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts#:~:text=mode), [agent_policy_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/agent_policy_watch.test.ts#:~:text=mode), [agent_policy_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/agent_policy_watch.test.ts#:~:text=mode) | 8.8.0 | -| | [security.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/security/security.ts#:~:text=authc), [transform_api_keys.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/api_keys/transform_api_keys.ts#:~:text=authc), [security.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/api_keys/security.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/epm/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/epm/handlers.ts#:~:text=authc)+ 36 more | - | +| | [security.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/api_keys/security.ts#:~:text=authc), [security.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/security/security.ts#:~:text=authc), [transform_api_keys.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/api_keys/transform_api_keys.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/epm/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/epm/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/epm/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/epm/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/epm/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts#:~:text=authc), [handlers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts#:~:text=authc)+ 36 more | - | | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/public/applications/integrations/index.tsx#:~:text=appBasePath) | 8.8.0 | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/saved_objects/index.ts#:~:text=migrations), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/saved_objects/index.ts#:~:text=migrations), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/saved_objects/index.ts#:~:text=migrations), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/saved_objects/index.ts#:~:text=migrations), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/saved_objects/index.ts#:~:text=migrations) | - | | | [audit_logging.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/audit_logging.ts#:~:text=audit), [audit_logging.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/fleet/server/services/audit_logging.ts#:~:text=audit) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index e2a11bb37fbeeb..73a33c4668a804 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index b1acedbda07888..953a9839ff37a9 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 8d22aab285ac8e..e364ccc82a307a 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index b47659da336f78..c77515d70677e4 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/discover_shared.mdx b/api_docs/discover_shared.mdx index 21118b394b1f09..915e355fd79e4b 100644 --- a/api_docs/discover_shared.mdx +++ b/api_docs/discover_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverShared title: "discoverShared" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverShared plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverShared'] --- import discoverSharedObj from './discover_shared.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index b5a2b4407a973d..1a6f9e9575cd94 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index ddefb78f3f8cac..441403cde90671 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 78357e670b1d30..76871e6e680839 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index d3796002050036..e04871b3b1db93 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index 6dc6fa126e5cbb..8d9ac944789712 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index 7b9bc0486ac5a6..1f3003a64cb9b3 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 085d9250db7d2d..8108a8b6776ee1 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/esql_data_grid.mdx b/api_docs/esql_data_grid.mdx index 72031c874283e6..529e5bfc24b8cf 100644 --- a/api_docs/esql_data_grid.mdx +++ b/api_docs/esql_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esqlDataGrid title: "esqlDataGrid" image: https://source.unsplash.com/400x175/?github description: API docs for the esqlDataGrid plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esqlDataGrid'] --- import esqlDataGridObj from './esql_data_grid.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 18f08b38368011..1c9e14ba90492c 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index 8f278710bd2607..d45db1f6914e6b 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index f80eb5d14ca369..da36e99e65ca2d 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/exploratory_view.mdx b/api_docs/exploratory_view.mdx index 9fb1c4a93b73d6..0025d08edc1711 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'exploratoryView'] --- import exploratoryViewObj from './exploratory_view.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 46b2d052a25ee4..01eafa01dee305 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 2f6494cdace315..925852e77d69b7 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index c299a0d3d34ab8..8aa5f4462cf5f3 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index c0b7995afcb518..bba400d1b3045f 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index b3e5312e8410cd..1a303f42e9638c 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index 4f2f34f6bbd6e8..0ffcf4d1ee5bd9 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index ffa7aae0cf6724..305b36fdb62077 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index b11b0ba0073d4a..0cbea72f7563c6 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index 4670ef58d76c55..c35b81f9083150 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index 90563de6cee2ea..78a57072b2ae29 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index ac420ce8974edb..3fa4ac3f62b0f1 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index 6ab9a7d1674ced..4452aa394f13c1 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index 39aa22a1e86b9b..626bd0655b3dc1 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 3a884971b1b90b..ad99535b03f13e 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 0b4da5be483d78..a319f1537ccf52 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index cbad887301cc26..bb88bdc3705a7d 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/fields_metadata.mdx b/api_docs/fields_metadata.mdx index 4154fe2cd85f1c..ce996ad370aa52 100644 --- a/api_docs/fields_metadata.mdx +++ b/api_docs/fields_metadata.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldsMetadata title: "fieldsMetadata" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldsMetadata plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldsMetadata'] --- import fieldsMetadataObj from './fields_metadata.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index ace9a985bc18b9..790b8fc5cff155 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 5c0bee1ea0c596..a2fd13d1c99648 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index 2356f96b7cd325..5147aec2df8abc 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index 4cae24c9356cc1..eccb9aef35f1bc 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -3384,10 +3384,10 @@ "id": "def-public.UIExtensionsStorage.Unnamed", "type": "IndexSignature", "tags": [], - "label": "[key: string]: Partial>", + "label": "[key: string]: Partial>", "description": [], "signature": [ - "[key: string]: Partial | undefined; aggregations?: Record | undefined; }>" ], @@ -21293,6 +21299,22 @@ "path": "x-pack/plugins/fleet/common/types/models/agent.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.FleetServerAgent.namespaces", + "type": "Array", + "tags": [], + "label": "namespaces", + "description": [ + "\nNamespaces" + ], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/fleet/common/types/models/agent.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 85574cf7f3c989..75c84f6c1d72ba 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1337 | 5 | 1216 | 71 | +| 1338 | 5 | 1216 | 72 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 76624d27343ab5..215446f0c0bb3d 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index 8f8c66cf87d7da..a86418e1b03d69 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index b4abbc90b216fc..d08cb4c662cf90 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index d23eecf1080b70..1025665cd37ed3 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index d07eb6950d5b48..03bb198df26a7e 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 313b2019871f57..1942fce8dc4b34 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 5e5e50c45f4ea6..adf5bec595e959 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/ingest_pipelines.mdx b/api_docs/ingest_pipelines.mdx index fb90e61284459a..fbf0e38e34f545 100644 --- a/api_docs/ingest_pipelines.mdx +++ b/api_docs/ingest_pipelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ingestPipelines title: "ingestPipelines" image: https://source.unsplash.com/400x175/?github description: API docs for the ingestPipelines plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ingestPipelines'] --- import ingestPipelinesObj from './ingest_pipelines.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index b950ff64040051..14af91942d5bb7 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/integration_assistant.mdx b/api_docs/integration_assistant.mdx index bb862840a8d1d2..3843c88387c928 100644 --- a/api_docs/integration_assistant.mdx +++ b/api_docs/integration_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/integrationAssistant title: "integrationAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the integrationAssistant plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'integrationAssistant'] --- import integrationAssistantObj from './integration_assistant.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index ec0a89a966912f..357d85637bd47a 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/investigate.mdx b/api_docs/investigate.mdx index 4d93088efa8788..8de337c3c95d46 100644 --- a/api_docs/investigate.mdx +++ b/api_docs/investigate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigate title: "investigate" image: https://source.unsplash.com/400x175/?github description: API docs for the investigate plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigate'] --- import investigateObj from './investigate.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 7ce881579a5a7b..b06c821e80cdae 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index b02a2a9d21a6a7..fa8abc5d1abe4a 100644 --- a/api_docs/kbn_actions_types.mdx +++ b/api_docs/kbn_actions_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-actions-types title: "@kbn/actions-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/actions-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index e1a8e798f160c8..01e342ac33cb78 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_pattern_analysis.mdx b/api_docs/kbn_aiops_log_pattern_analysis.mdx index 72eede9d9fd82d..ff4acdfbeb7597 100644 --- a/api_docs/kbn_aiops_log_pattern_analysis.mdx +++ b/api_docs/kbn_aiops_log_pattern_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-pattern-analysis title: "@kbn/aiops-log-pattern-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-pattern-analysis plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-pattern-analysis'] --- import kbnAiopsLogPatternAnalysisObj from './kbn_aiops_log_pattern_analysis.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_rate_analysis.mdx b/api_docs/kbn_aiops_log_rate_analysis.mdx index b6589e7e5c8a64..ec680f789947b5 100644 --- a/api_docs/kbn_aiops_log_rate_analysis.mdx +++ b/api_docs/kbn_aiops_log_rate_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-rate-analysis title: "@kbn/aiops-log-rate-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-rate-analysis plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-rate-analysis'] --- import kbnAiopsLogRateAnalysisObj from './kbn_aiops_log_rate_analysis.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index b30d9b247986a3..227b93cbe6c809 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_comparators.mdx b/api_docs/kbn_alerting_comparators.mdx index 3ff7cd7b524ea9..e8909afd96cd6e 100644 --- a/api_docs/kbn_alerting_comparators.mdx +++ b/api_docs/kbn_alerting_comparators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-comparators title: "@kbn/alerting-comparators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-comparators plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-comparators'] --- import kbnAlertingComparatorsObj from './kbn_alerting_comparators.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 59f71bb7d06a4a..7162776bea72e0 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerting_types.mdx b/api_docs/kbn_alerting_types.mdx index 1fa5967e92c767..df3d3c1ebde231 100644 --- a/api_docs/kbn_alerting_types.mdx +++ b/api_docs/kbn_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-types title: "@kbn/alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-types'] --- import kbnAlertingTypesObj from './kbn_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 0f54660851da3f..4abb5875169158 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 6a8ace9a32049c..487d845867b34a 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index f61a72c328c9fe..e46bfe5940a947 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index f9e06eed6bb645..45cdad52bc478e 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index fc3bb389ac23d0..351c1e8690d63d 100644 --- a/api_docs/kbn_analytics_collection_utils.mdx +++ b/api_docs/kbn_analytics_collection_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-collection-utils title: "@kbn/analytics-collection-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-collection-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index 8a108028990339..a1fc0621373345 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 555450cec3ae8e..530d29f8d6ee82 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index 64e8755f22ef9b..536f741488ff9d 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index 7ff9f68c236d5f..6d5fbaf58357b0 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index bfdfd2f4f74c58..d98fbe3570141e 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_data_view.mdx b/api_docs/kbn_apm_data_view.mdx index 42348387533e9c..307aeb06fe7b0d 100644 --- a/api_docs/kbn_apm_data_view.mdx +++ b/api_docs/kbn_apm_data_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-data-view title: "@kbn/apm-data-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-data-view plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-data-view'] --- import kbnApmDataViewObj from './kbn_apm_data_view.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 27d6759bd25617..d16fad88bde1c7 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 9f40bdce1dbdcc..5d4077f25f851f 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 4763291740a71d..4078b2b9924981 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index 2f3bee6b0080b9..a86bfa4aba3dc4 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bfetch_error.mdx b/api_docs/kbn_bfetch_error.mdx index c6169289264101..dfab0800e2a0f0 100644 --- a/api_docs/kbn_bfetch_error.mdx +++ b/api_docs/kbn_bfetch_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bfetch-error title: "@kbn/bfetch-error" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bfetch-error plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bfetch-error'] --- import kbnBfetchErrorObj from './kbn_bfetch_error.devdocs.json'; diff --git a/api_docs/kbn_calculate_auto.mdx b/api_docs/kbn_calculate_auto.mdx index 92dc69482554bc..a831688cd6a16c 100644 --- a/api_docs/kbn_calculate_auto.mdx +++ b/api_docs/kbn_calculate_auto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-auto title: "@kbn/calculate-auto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-auto plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-auto'] --- import kbnCalculateAutoObj from './kbn_calculate_auto.devdocs.json'; diff --git a/api_docs/kbn_calculate_width_from_char_count.mdx b/api_docs/kbn_calculate_width_from_char_count.mdx index 4f2c217badd05c..56e46c2ac595e1 100644 --- a/api_docs/kbn_calculate_width_from_char_count.mdx +++ b/api_docs/kbn_calculate_width_from_char_count.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-width-from-char-count title: "@kbn/calculate-width-from-char-count" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-width-from-char-count plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-width-from-char-count'] --- import kbnCalculateWidthFromCharCountObj from './kbn_calculate_width_from_char_count.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 113c5038fcdd3a..88e2fe42a4fec3 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 23dab4eb264dd5..43e66d95034f75 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index e4b859e84188f1..73f3e636779ac4 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index 36c62cf75e461d..a39b164e2e0668 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-icons'] --- import kbnChartIconsObj from './kbn_chart_icons.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index af73a6f2672b0f..7b14acf65b8385 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index 4aa785c60d7f27..ed9607d16f834d 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 5e7638dad0389d..a8c36eed58e93f 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index a47825df146d70..cf0dac9edba01c 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index f0f1803d1d9fc5..dfa158ac1ec18d 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mock.mdx b/api_docs/kbn_code_editor_mock.mdx index 2c0792fd28f0f6..54c2b42c47d0f4 100644 --- a/api_docs/kbn_code_editor_mock.mdx +++ b/api_docs/kbn_code_editor_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mock title: "@kbn/code-editor-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mock plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mock'] --- import kbnCodeEditorMockObj from './kbn_code_editor_mock.devdocs.json'; diff --git a/api_docs/kbn_code_owners.mdx b/api_docs/kbn_code_owners.mdx index 3517204bd45b19..a4509947484f8d 100644 --- a/api_docs/kbn_code_owners.mdx +++ b/api_docs/kbn_code_owners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-owners title: "@kbn/code-owners" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-owners plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-owners'] --- import kbnCodeOwnersObj from './kbn_code_owners.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 3b1af9d2a81705..1ad88c024bbf82 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 6502279e9947ed..9b875d1e2e2acc 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index dcaaa854f0382c..e0e354ab7ad5d9 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 3d675e06d2fcc1..bb150234272260 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index f60a3981386a29..37dd4c0061cc29 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index 8a4e4c5955ef63..b472318320313e 100644 --- a/api_docs/kbn_content_management_tabbed_table_list_view.mdx +++ b/api_docs/kbn_content_management_tabbed_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-tabbed-table-list-view title: "@kbn/content-management-tabbed-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-tabbed-table-list-view plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-tabbed-table-list-view'] --- import kbnContentManagementTabbedTableListViewObj from './kbn_content_management_tabbed_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view.mdx b/api_docs/kbn_content_management_table_list_view.mdx index 36028ba05cfa8e..5b851e5384110e 100644 --- a/api_docs/kbn_content_management_table_list_view.mdx +++ b/api_docs/kbn_content_management_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view title: "@kbn/content-management-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view'] --- import kbnContentManagementTableListViewObj from './kbn_content_management_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_common.mdx b/api_docs/kbn_content_management_table_list_view_common.mdx index 805f07c38bf79f..eaacdb815fed9d 100644 --- a/api_docs/kbn_content_management_table_list_view_common.mdx +++ b/api_docs/kbn_content_management_table_list_view_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-common title: "@kbn/content-management-table-list-view-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-common'] --- import kbnContentManagementTableListViewCommonObj from './kbn_content_management_table_list_view_common.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index ee635383e39cd0..b204e4dbf83740 100644 --- a/api_docs/kbn_content_management_table_list_view_table.mdx +++ b/api_docs/kbn_content_management_table_list_view_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-table title: "@kbn/content-management-table-list-view-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-table plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 20536a7d3bad80..95d831172342ad 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 54ae0bad6081e1..5e8fb7e681138f 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index edfc4a38ef36ff..79058a9a104e2d 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 1118dc0bff1c0b..6c6b2b592bb48e 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 8b08b6e8f6004b..b1281d75c3b3de 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index 4afef1d927b977..7de21c211151cb 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index eccfc56adb329c..713977cd2472c2 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser.mdx b/api_docs/kbn_core_application_browser.mdx index 60950431b91bf5..f251d7a1c93507 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser'] --- import kbnCoreApplicationBrowserObj from './kbn_core_application_browser.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_internal.mdx b/api_docs/kbn_core_application_browser_internal.mdx index 65de855ca3ee73..f981d646c6fb37 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-internal'] --- import kbnCoreApplicationBrowserInternalObj from './kbn_core_application_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_mocks.mdx b/api_docs/kbn_core_application_browser_mocks.mdx index a8da82ee1bef52..bef8995e9654bd 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-mocks'] --- import kbnCoreApplicationBrowserMocksObj from './kbn_core_application_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_common.mdx b/api_docs/kbn_core_application_common.mdx index 24f0cfed4a457b..16145d3c11fafc 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-common'] --- import kbnCoreApplicationCommonObj from './kbn_core_application_common.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_internal.mdx b/api_docs/kbn_core_apps_browser_internal.mdx index 6028c3344a7762..18fcb5acd1646d 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-internal'] --- import kbnCoreAppsBrowserInternalObj from './kbn_core_apps_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_mocks.mdx b/api_docs/kbn_core_apps_browser_mocks.mdx index a56db7522934ef..e08586791cb808 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index 4ff38183b9eac6..b295697eba559d 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index aaef90a451f78f..eee3e8ec637f93 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index bfdd1e2df9b27e..94aacc78b60c15 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 8e7da7d8d609ed..970a80356039fc 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index d8c8bba1ba4797..a3ee47d6811bfa 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_browser_mocks.mdx b/api_docs/kbn_core_capabilities_browser_mocks.mdx index b838e24edeea94..1b9697f69616d3 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-browser-mocks'] --- import kbnCoreCapabilitiesBrowserMocksObj from './kbn_core_capabilities_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 20fc610aa4381b..30cceca53d2ebd 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index 4d5af3e83a8177..cc6cb4c39c1c21 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 5cba8debee929e..12c6007f628482 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 687bbc4fe712ee..df65336afe5387 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index c25ff5885aa261..5381f189870cb9 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser-mocks'] --- import kbnCoreChromeBrowserMocksObj from './kbn_core_chrome_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index f774814ff20f3f..6794b366689c15 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 0a3ed60dd03cf2..4ff34e4adefc22 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index e272909a893d14..e81870b643c879 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index 67938b5aa490ce..6617eb567d073a 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index 545d7ac7296236..d84a80e9e697b8 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index bc6a970b2a23c8..7b61b93bf6cc9f 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index c786d9af3f46e2..31cfa4d4e45f9f 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index d6598828b3dad6..bf2dd1174975c6 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index b105bd2524d978..2c5c656d5a1738 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index 6acaff9e710658..0eef07d37f2f67 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index fb76520008b479..c48a04beced54c 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index 5474924b12a231..368228a7244506 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server.mdx b/api_docs/kbn_core_deprecations_server.mdx index bfaac5d4c2911e..189c9acfe34dc7 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server'] --- import kbnCoreDeprecationsServerObj from './kbn_core_deprecations_server.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_internal.mdx b/api_docs/kbn_core_deprecations_server_internal.mdx index d9897bcbb6457f..4f27d9d7bdc27a 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-internal'] --- import kbnCoreDeprecationsServerInternalObj from './kbn_core_deprecations_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_mocks.mdx b/api_docs/kbn_core_deprecations_server_mocks.mdx index 6ee40f9d97e541..a6780bf1df2ea8 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-mocks'] --- import kbnCoreDeprecationsServerMocksObj from './kbn_core_deprecations_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index 634e3f9e133744..40fdbe57f7aec7 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index 24926823d958b2..90d2f8adc9c27a 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 487937b9b0f288..347b7e5ca73722 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 588c1dda6a075b..1d06db5d65017a 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index 0714d977d7c3ad..dffaee0aef2270 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 0b86a9c512fdeb..078d393221f854 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 3ba50b8dac16d0..1b33d6e1e1d435 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index da80cfb3311b51..78c2fb36d6e18e 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 9ac7f069b22a18..81c7b543e5a395 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index ca8f782cf8fdbe..e9c8b9fb706e45 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index 7e658cb729e0ef..201c9d3d19e46f 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index f98419701821e8..3a7e7795ab0de9 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 6ea0c9944d1fab..56201fe91ba97b 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index 2ee9ef3b28c0b2..d8f2b10177c2ab 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index dce842b6af2bbf..2b252e07e33858 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index bac03638177b98..66a96931f2fcc8 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index 9644cfce33b384..dab20d8cc1900d 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index cba891baf2822f..0563ccd1b81654 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index fe9b84a3c32173..12072174cb8f0b 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index dc698f6bc28ab0..acef91e377e5ef 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index b0e6c6e4c27c49..6cd249cc3e4df7 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 18144b1e9448b7..4e94ae5e5a8f15 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index ddd4fbfe4177ae..6c1070c0eaf011 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index 018af3ce1b3859..8fc34ad8c65e18 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index 01ffe716633704..44fc25a15d19e3 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index d638b044dad2a4..abb6ef52263091 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index cab6799bff0b38..dcca80ea28e061 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index 4c12f16c2a8eac..509693ecd745a7 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index 71549eaf13b6fd..8a70bb7f215a61 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index c3373fbd0c0275..c7b81733f49913 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index 132723544a7150..ee3e10bf451476 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index a02429ead643f6..c59369bdb598ac 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 54fc0400180d9b..94a84e11ee872b 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index a66c00bf850507..398c4b490aeffb 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 308810c2f34dbd..cef2050e92def1 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index f3f58f1e598be6..a0e66b8eab87cd 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index ad5674f53c4aee..5fc017df1af979 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index 7d14a5df1cac90..7942a398e549b0 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index 940c59e35302ff..95e656990580d8 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 2cd31138fa05b4..00307bd30d48f3 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index a1fb8ddc8f01a1..9a3d9633892ee6 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index 984367351f0a08..30f7e9f75dbfc4 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index 7a21a006540410..b0c301e1425d0e 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index 5a462ff9dd9b24..ddec0ce7847f4e 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index cb87edb50dd307..7ec9130a81c25e 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index 13631df322a0c3..9d93dec58ef0bc 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index 781c290efa830b..d75280e591054e 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index d01c51fedc3710..1528d1873342dd 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index c803551f96ee75..a9e1c8beb172aa 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 911eca5d9eacf7..09c173f792ef9d 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 12d3f8850d6d36..272ce8ea971a34 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index a3f43b920d8755..767835c5efb7d8 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 7f3cf59bd52506..7f468539935324 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index 1588ea886fcd2a..741ada65111196 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 1d3b030a44635a..20cc76f5b09ef2 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index 45da69c906fc39..e99b6d6168e727 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 1827a3566ec820..0214af178c9f07 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index e921adbc4a2e31..65540f34578971 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index f943b333f9792a..61f89ff5f2cb32 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index 80e3a0fbda28f2..ec3d7f9b861295 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index ca2ee8d57e1b02..79310036bbe9a6 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index 09b9d84416b03b..a3998cca34a3a8 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index 2bc91692e377f5..45310c0840b606 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 37f8d8d8565fa3..c85edd3257f91b 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index 52a6975ec03396..3393b2a4021216 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 64617ce9241728..5d69b7ee580e02 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index b7af11e6f7f58c..f0cae503b4f1c6 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index b7309fd3076234..99d1abe125a68e 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index b3f413fd8b8045..6c97ce67d86a45 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index 96c99c1dec0975..88aba70f779258 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 2819726083c7e8..247f7c81352146 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 9fe038fd41f71f..0810e0ba2d7594 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index ce5a9415292463..a1ad60f25d392f 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index c6b8a7cfcaef0f..f20648b50a0b16 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index 4e99f055d2e1d9..5de01f17af3716 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index ada8d4c859f55d..5fb49017a91587 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index 15ca4c2aad1a23..4291832fd0738f 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 0a43ac9803d0a8..a6dcf012a32531 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 67b30a802e9b67..fba55c27a9059d 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 7dbb108d55d255..1f4246ce25225d 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index d1f83921f99882..c313d47ec8a2f7 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index acf4f86f23f467..df005b36ab1619 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index fc17a91ed817cd..6a03625c7cbeca 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index 803a3105865abf..ebe9f47d41e467 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 88af27b56f3d2e..2eddae6645152b 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 621a80d312fc26..820ca0283b29e3 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index e56f6b4af841f3..b4ba29e7cd7ac0 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index bad755357fef83..318f9346661351 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index 003b968a383067..61bd3b20ba2126 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index 6ab936bd508cd3..007e6d0007869a 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index a8e76cbb3f9ae9..b287508e816f6a 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 0908b45816b605..e60781764e9dd0 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 89c43629a3292c..0ebdb8b26557d7 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index 894ac8196e237b..4b2a55c6e396c1 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index 6be3737457dbfb..43cfbead9833d1 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser.mdx b/api_docs/kbn_core_security_browser.mdx index 52170683384259..5be1e78d5da9d6 100644 --- a/api_docs/kbn_core_security_browser.mdx +++ b/api_docs/kbn_core_security_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser title: "@kbn/core-security-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser'] --- import kbnCoreSecurityBrowserObj from './kbn_core_security_browser.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_internal.mdx b/api_docs/kbn_core_security_browser_internal.mdx index d8714baa918089..991a583cc5e127 100644 --- a/api_docs/kbn_core_security_browser_internal.mdx +++ b/api_docs/kbn_core_security_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-internal title: "@kbn/core-security-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-internal'] --- import kbnCoreSecurityBrowserInternalObj from './kbn_core_security_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_mocks.mdx b/api_docs/kbn_core_security_browser_mocks.mdx index 5483add06f3aab..c3c1737fdc9ab5 100644 --- a/api_docs/kbn_core_security_browser_mocks.mdx +++ b/api_docs/kbn_core_security_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-mocks title: "@kbn/core-security-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-mocks'] --- import kbnCoreSecurityBrowserMocksObj from './kbn_core_security_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_security_common.mdx b/api_docs/kbn_core_security_common.mdx index 3160159c8d12e3..9670c5a59d448b 100644 --- a/api_docs/kbn_core_security_common.mdx +++ b/api_docs/kbn_core_security_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-common title: "@kbn/core-security-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-common'] --- import kbnCoreSecurityCommonObj from './kbn_core_security_common.devdocs.json'; diff --git a/api_docs/kbn_core_security_server.mdx b/api_docs/kbn_core_security_server.mdx index 84c08982385c4d..35be18d36b1581 100644 --- a/api_docs/kbn_core_security_server.mdx +++ b/api_docs/kbn_core_security_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server title: "@kbn/core-security-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server'] --- import kbnCoreSecurityServerObj from './kbn_core_security_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_internal.mdx b/api_docs/kbn_core_security_server_internal.mdx index e107bb2d34ed82..3b0ec3fe786994 100644 --- a/api_docs/kbn_core_security_server_internal.mdx +++ b/api_docs/kbn_core_security_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-internal title: "@kbn/core-security-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-internal'] --- import kbnCoreSecurityServerInternalObj from './kbn_core_security_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_mocks.mdx b/api_docs/kbn_core_security_server_mocks.mdx index d086b678038a00..ac515de31e89e0 100644 --- a/api_docs/kbn_core_security_server_mocks.mdx +++ b/api_docs/kbn_core_security_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-mocks title: "@kbn/core-security-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-mocks'] --- import kbnCoreSecurityServerMocksObj from './kbn_core_security_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index 39567b1b1bd642..dc33a315941e4c 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index d5bde0a90cbd53..b843121cbd69aa 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index 644cf7f96a29f0..ed4b208f4a796a 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index 3774ed1d3e233f..71ea68f7d5ba9d 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index 7ddefdf2c43c06..cc69f9a7c81753 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index d9dc4054aabef9..0b27924382ad52 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index ac9e10ddf7292d..f937cd2d8a0a83 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index 4aebf41ce691cf..ac242965cda10a 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index e74db79812b591..7a5d6babab383e 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index ac918665f42acd..bc9bd5e6045196 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index 7172faff3f4bc2..e21547444a2005 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 3f8e46e816bf5b..1c73e73b8e24da 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 3a43a7c1f9a7fd..9762a0bf00d2f2 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 35bea4f0951ca9..6fc4bbaceccfa2 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 4a57fb3b803257..098a43228e2119 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index b6cce92505cb9d..a678369d6eb6c0 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index aa5258399d4de2..50f6a33ada34ed 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index 12af0f5b7e5892..ae5457505b3775 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index 5c63ba00710a43..dda6040547258d 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index 07f69e99e154fe..50bc0277179521 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index 73857d7c42f59d..9f5d7558f0cdee 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index a3d229869e4424..44e691739a9a42 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index d1ecca5536282d..b5853c26912dd7 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser.mdx b/api_docs/kbn_core_user_profile_browser.mdx index 56eac696e81a32..3f847bb3cbb7ba 100644 --- a/api_docs/kbn_core_user_profile_browser.mdx +++ b/api_docs/kbn_core_user_profile_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser title: "@kbn/core-user-profile-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser'] --- import kbnCoreUserProfileBrowserObj from './kbn_core_user_profile_browser.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_internal.mdx b/api_docs/kbn_core_user_profile_browser_internal.mdx index f3bc401c4d717a..bbcb96fe8d840b 100644 --- a/api_docs/kbn_core_user_profile_browser_internal.mdx +++ b/api_docs/kbn_core_user_profile_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-internal title: "@kbn/core-user-profile-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-internal'] --- import kbnCoreUserProfileBrowserInternalObj from './kbn_core_user_profile_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_mocks.mdx b/api_docs/kbn_core_user_profile_browser_mocks.mdx index dae1988c059e9d..c95de8602f92e1 100644 --- a/api_docs/kbn_core_user_profile_browser_mocks.mdx +++ b/api_docs/kbn_core_user_profile_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-mocks title: "@kbn/core-user-profile-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-mocks'] --- import kbnCoreUserProfileBrowserMocksObj from './kbn_core_user_profile_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_common.mdx b/api_docs/kbn_core_user_profile_common.mdx index 857870c56a06e2..e76fb89ad8be0e 100644 --- a/api_docs/kbn_core_user_profile_common.mdx +++ b/api_docs/kbn_core_user_profile_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-common title: "@kbn/core-user-profile-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-common'] --- import kbnCoreUserProfileCommonObj from './kbn_core_user_profile_common.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server.mdx b/api_docs/kbn_core_user_profile_server.mdx index 152119caae184d..ef92831535c47d 100644 --- a/api_docs/kbn_core_user_profile_server.mdx +++ b/api_docs/kbn_core_user_profile_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server title: "@kbn/core-user-profile-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server'] --- import kbnCoreUserProfileServerObj from './kbn_core_user_profile_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_internal.mdx b/api_docs/kbn_core_user_profile_server_internal.mdx index 9b04678da2d5d4..422f1ce5a92bbe 100644 --- a/api_docs/kbn_core_user_profile_server_internal.mdx +++ b/api_docs/kbn_core_user_profile_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-internal title: "@kbn/core-user-profile-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-internal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-internal'] --- import kbnCoreUserProfileServerInternalObj from './kbn_core_user_profile_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_mocks.mdx b/api_docs/kbn_core_user_profile_server_mocks.mdx index 50c2b3f82f8eb4..6e82292c8f67a0 100644 --- a/api_docs/kbn_core_user_profile_server_mocks.mdx +++ b/api_docs/kbn_core_user_profile_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-mocks title: "@kbn/core-user-profile-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-mocks'] --- import kbnCoreUserProfileServerMocksObj from './kbn_core_user_profile_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index 865370737cbafd..bb2abf7052d1a4 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index 7e6dccebc55649..e0530e82a349cd 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index f02b3fb496e02f..8d6830288901c4 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index d8a7a6ecd269e7..34122d21f55587 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_icons.mdx b/api_docs/kbn_custom_icons.mdx index f1832a8e4a3f87..5c9edfafda6dd5 100644 --- a/api_docs/kbn_custom_icons.mdx +++ b/api_docs/kbn_custom_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-icons title: "@kbn/custom-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-icons plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-icons'] --- import kbnCustomIconsObj from './kbn_custom_icons.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index 609a64e4a99695..2a1a10905c5e92 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index f6ffe6dea55437..24d57726f53c4d 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_forge.mdx b/api_docs/kbn_data_forge.mdx index c318399e873c8f..6c552996443a5b 100644 --- a/api_docs/kbn_data_forge.mdx +++ b/api_docs/kbn_data_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-forge title: "@kbn/data-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-forge plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-forge'] --- import kbnDataForgeObj from './kbn_data_forge.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 1b7c35fd2325ca..56d6b807dcf962 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_data_stream_adapter.mdx b/api_docs/kbn_data_stream_adapter.mdx index fee26fa0f2e094..d7755afb4bd0cf 100644 --- a/api_docs/kbn_data_stream_adapter.mdx +++ b/api_docs/kbn_data_stream_adapter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-stream-adapter title: "@kbn/data-stream-adapter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-stream-adapter plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-stream-adapter'] --- import kbnDataStreamAdapterObj from './kbn_data_stream_adapter.devdocs.json'; diff --git a/api_docs/kbn_data_view_utils.mdx b/api_docs/kbn_data_view_utils.mdx index c72ac137a43761..3f9cfd3e15bacd 100644 --- a/api_docs/kbn_data_view_utils.mdx +++ b/api_docs/kbn_data_view_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-view-utils title: "@kbn/data-view-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-view-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-view-utils'] --- import kbnDataViewUtilsObj from './kbn_data_view_utils.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index d320f47f2bd5fd..9bb9de5ed5471f 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index f436699b2259e0..6f5b8882c4f5ae 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index ca4ba92762b061..f4757ad7d18763 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_fleet.mdx b/api_docs/kbn_deeplinks_fleet.mdx index 32edbfb233579e..96f0c8c0341cb3 100644 --- a/api_docs/kbn_deeplinks_fleet.mdx +++ b/api_docs/kbn_deeplinks_fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-fleet title: "@kbn/deeplinks-fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-fleet plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-fleet'] --- import kbnDeeplinksFleetObj from './kbn_deeplinks_fleet.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index 7d93d245922a7f..8b229f4cc19f8b 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index 30f6072ee703ae..cc069e178f4bc1 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index 6672a659c774b2..d824e8064b963e 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index 9837a908384257..555bbbf62fdc21 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_security.mdx b/api_docs/kbn_deeplinks_security.mdx index b4c29d128b7bc7..3a0f870d4b3354 100644 --- a/api_docs/kbn_deeplinks_security.mdx +++ b/api_docs/kbn_deeplinks_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-security title: "@kbn/deeplinks-security" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-security plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-security'] --- import kbnDeeplinksSecurityObj from './kbn_deeplinks_security.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_shared.mdx b/api_docs/kbn_deeplinks_shared.mdx index 17fb23756b2e99..f6f6ad56ad9461 100644 --- a/api_docs/kbn_deeplinks_shared.mdx +++ b/api_docs/kbn_deeplinks_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-shared title: "@kbn/deeplinks-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-shared plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-shared'] --- import kbnDeeplinksSharedObj from './kbn_deeplinks_shared.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index c85c1c3dbc9d5b..e14dddf6997f91 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index fa0d410971f6d8..243fd8639335c5 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index c40a95f8bb0d8f..8c800bbe4517e8 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index 5bf44493705955..face43c46780e4 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index c708bfe8d087be..1217a0ca13fa9b 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 6520201f20bb3d..9d914ba9978e52 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index bf577bba438ee6..c59ecdf80707bf 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 3cb448a38ebfda..4a501d42c4ebd1 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 6852b0a1a51c4a..ff6d52f0aec76d 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index e46fcf304bc832..a0be6948d2da62 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -840,7 +840,7 @@ "label": "fleet", "description": [], "signature": [ - "{ readonly beatsAgentComparison: string; readonly guide: string; readonly fleetServer: string; readonly fleetServerAddFleetServer: string; readonly esSettings: string; readonly settings: string; readonly logstashSettings: string; readonly kafkaSettings: string; readonly settingsFleetServerHostSettings: string; readonly settingsFleetServerProxySettings: string; readonly troubleshooting: string; readonly elasticAgent: string; readonly datastreams: string; readonly datastreamsILM: string; readonly datastreamsNamingScheme: string; readonly datastreamsManualRollover: string; readonly datastreamsTSDS: string; readonly datastreamsTSDSMetrics: string; readonly installElasticAgent: string; readonly installElasticAgentStandalone: string; readonly packageSignatures: string; readonly upgradeElasticAgent: string; readonly learnMoreBlog: string; readonly apiKeysLearnMore: string; readonly onPremRegistry: string; readonly secureLogstash: string; readonly agentPolicy: string; readonly api: string; readonly uninstallAgent: string; readonly installAndUninstallIntegrationAssets: string; readonly elasticAgentInputConfiguration: string; readonly policySecrets: string; readonly remoteESOoutput: string; readonly performancePresets: string; readonly scalingKubernetesResourcesAndLimits: string; readonly roleAndPrivileges: string; readonly proxiesSettings: string; }" + "{ readonly beatsAgentComparison: string; readonly guide: string; readonly fleetServer: string; readonly fleetServerAddFleetServer: string; readonly esSettings: string; readonly settings: string; readonly logstashSettings: string; readonly kafkaSettings: string; readonly settingsFleetServerHostSettings: string; readonly settingsFleetServerProxySettings: string; readonly troubleshooting: string; readonly elasticAgent: string; readonly datastreams: string; readonly datastreamsILM: string; readonly datastreamsNamingScheme: string; readonly datastreamsManualRollover: string; readonly datastreamsTSDS: string; readonly datastreamsTSDSMetrics: string; readonly datastreamsDownsampling: string; readonly installElasticAgent: string; readonly installElasticAgentStandalone: string; readonly packageSignatures: string; readonly upgradeElasticAgent: string; readonly learnMoreBlog: string; readonly apiKeysLearnMore: string; readonly onPremRegistry: string; readonly secureLogstash: string; readonly agentPolicy: string; readonly api: string; readonly uninstallAgent: string; readonly installAndUninstallIntegrationAssets: string; readonly elasticAgentInputConfiguration: string; readonly policySecrets: string; readonly remoteESOoutput: string; readonly performancePresets: string; readonly scalingKubernetesResourcesAndLimits: string; readonly roleAndPrivileges: string; readonly proxiesSettings: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 7b4148825dc72e..99b4070129b905 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 1fd1f16843d716..1c009ad6ae1fba 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index bfe12e9b85204e..ad520c4d0940df 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index ec03051ac4e035..ef632ce1a693c9 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index f607ea1d0be37f..6d0bfdecc32145 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_agent_utils.mdx b/api_docs/kbn_elastic_agent_utils.mdx index a0c780c5650b88..389bd6dfbcb13e 100644 --- a/api_docs/kbn_elastic_agent_utils.mdx +++ b/api_docs/kbn_elastic_agent_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-agent-utils title: "@kbn/elastic-agent-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-agent-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 8d75bbb7811cf2..822df19b8e86fa 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index 54c80273b84436..9e4c31025175de 100644 --- a/api_docs/kbn_elastic_assistant_common.mdx +++ b/api_docs/kbn_elastic_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant-common title: "@kbn/elastic-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_entities_schema.mdx b/api_docs/kbn_entities_schema.mdx index 25ff41cc02a9fb..198cfcc01bac47 100644 --- a/api_docs/kbn_entities_schema.mdx +++ b/api_docs/kbn_entities_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-entities-schema title: "@kbn/entities-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/entities-schema plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/entities-schema'] --- import kbnEntitiesSchemaObj from './kbn_entities_schema.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index ed9ab2f18ade22..34e75530265261 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index f006c212d642fd..fcd3764151fb15 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 6fa3326745f80a..a3c7ca961734e8 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 1176edac178e63..e952e747c1c0d3 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 7b7022d76d8ea4..f02fa1ee652b9d 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 1ae572d5d60437..1ea8516125ece9 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_esql_ast.mdx b/api_docs/kbn_esql_ast.mdx index f1946f2103183f..df1043fcfa395e 100644 --- a/api_docs/kbn_esql_ast.mdx +++ b/api_docs/kbn_esql_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-ast title: "@kbn/esql-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-ast plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-ast'] --- import kbnEsqlAstObj from './kbn_esql_ast.devdocs.json'; diff --git a/api_docs/kbn_esql_utils.mdx b/api_docs/kbn_esql_utils.mdx index 12ee66d88722be..821d90db7c9a31 100644 --- a/api_docs/kbn_esql_utils.mdx +++ b/api_docs/kbn_esql_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-utils title: "@kbn/esql-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-utils'] --- import kbnEsqlUtilsObj from './kbn_esql_utils.devdocs.json'; diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index f05c67a45f383a..8cf5a9051dac73 100644 --- a/api_docs/kbn_esql_validation_autocomplete.mdx +++ b/api_docs/kbn_esql_validation_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-validation-autocomplete title: "@kbn/esql-validation-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-validation-autocomplete plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-validation-autocomplete'] --- import kbnEsqlValidationAutocompleteObj from './kbn_esql_validation_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index 841b09da577048..195dcc7f252e42 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index bf0774a4b872e4..cd2ffd5dc03be0 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index 8334451525f44a..ddf980c7880954 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 4ff1ecb122add2..0dbb4516f899b5 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index cfe2c88beeb8f7..607e6e85b5b860 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 898ea10b60d181..5c30aa57582231 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_formatters.mdx b/api_docs/kbn_formatters.mdx index f81e9144143c9c..6badbde276ef97 100644 --- a/api_docs/kbn_formatters.mdx +++ b/api_docs/kbn_formatters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-formatters title: "@kbn/formatters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/formatters plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/formatters'] --- import kbnFormattersObj from './kbn_formatters.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 91f11d5537abc1..7d14b862832b89 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_ui_services.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index b05d6f283ebd17..0816a776cc2d8d 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.mdx +++ b/api_docs/kbn_ftr_common_functional_ui_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-ui-services title: "@kbn/ftr-common-functional-ui-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-ui-services plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-ui-services'] --- import kbnFtrCommonFunctionalUiServicesObj from './kbn_ftr_common_functional_ui_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 6baa9b9dfe1ebe..273f2e8ae97068 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index 683d3c79b9dcea..6e04d34d1e580f 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index c8a49fdc384914..89d00a9f4726bf 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index 3c198bd6da8014..c58584592fe2d5 100644 --- a/api_docs/kbn_grouping.mdx +++ b/api_docs/kbn_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grouping title: "@kbn/grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grouping plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grouping'] --- import kbnGroupingObj from './kbn_grouping.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index eaa0629e9bc625..f0c50d75baef50 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 1d2f299d4b79c1..92086810350eaf 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index 61a0941c5a5704..dc2e61157905c4 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index 3c5345798c4be0..8b15c7a2519458 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 1297af5fcf739f..2411e3232b526d 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index 81f2f008488817..df62efebdf0483 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index 9a818429802c83..00596b5b411622 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index 3ece92db0599ca..5b9256cbf9013e 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index eb37e77be049c0..994dc23e2cdeec 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_index_management.mdx b/api_docs/kbn_index_management.mdx index ebd0afbce2dbc2..4216389c07d072 100644 --- a/api_docs/kbn_index_management.mdx +++ b/api_docs/kbn_index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-management title: "@kbn/index-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-management plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-management'] --- import kbnIndexManagementObj from './kbn_index_management.devdocs.json'; diff --git a/api_docs/kbn_inference_integration_flyout.mdx b/api_docs/kbn_inference_integration_flyout.mdx index 04278a93686549..2fd7b7701b5a5a 100644 --- a/api_docs/kbn_inference_integration_flyout.mdx +++ b/api_docs/kbn_inference_integration_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-inference_integration_flyout title: "@kbn/inference_integration_flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/inference_integration_flyout plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/inference_integration_flyout'] --- import kbnInferenceIntegrationFlyoutObj from './kbn_inference_integration_flyout.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index df458c4c1210e1..a70f1d03f26a11 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 79a9c6d210c073..e17dbf002a9658 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 3c4303a5f9a79c..09c2f90cf9a647 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_ipynb.mdx b/api_docs/kbn_ipynb.mdx index d51b3917d6d962..613484e3bcc1bd 100644 --- a/api_docs/kbn_ipynb.mdx +++ b/api_docs/kbn_ipynb.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ipynb title: "@kbn/ipynb" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ipynb plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ipynb'] --- import kbnIpynbObj from './kbn_ipynb.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 47e552cffa1844..c199e942c47367 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index d8802796021ba3..2168b894799536 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index 8583d1fda3efad..7b38a3b47dbbe1 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 13e63c8d66a2ff..e069b954427bd9 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx index f01e4d1748628c..a694f2381cdb4d 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index 9d7934ba53dc10..654988afdd9ad7 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_lens_formula_docs.mdx b/api_docs/kbn_lens_formula_docs.mdx index e89d5d7cc98442..389fc614a9d046 100644 --- a/api_docs/kbn_lens_formula_docs.mdx +++ b/api_docs/kbn_lens_formula_docs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-formula-docs title: "@kbn/lens-formula-docs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-formula-docs plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-formula-docs'] --- import kbnLensFormulaDocsObj from './kbn_lens_formula_docs.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index ff90fecc0dd792..ac5cc472bd957a 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index 8178a1391b9765..a7c06f39b88911 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_content_badge.mdx b/api_docs/kbn_managed_content_badge.mdx index 57cc3d36498691..c1e7cc6cb29508 100644 --- a/api_docs/kbn_managed_content_badge.mdx +++ b/api_docs/kbn_managed_content_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-content-badge title: "@kbn/managed-content-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-content-badge plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-content-badge'] --- import kbnManagedContentBadgeObj from './kbn_managed_content_badge.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index 91a8523bded27e..c4805f5d06330f 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index dc976309ee1dff..fa34a83354fba2 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index 60864907575121..a35cbf8d26019b 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index da4190ad3046ea..be9c1a2e0b319a 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index ca15e140f86609..35b8de7da86532 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index d819a114483b46..e32b94df5ef883 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index 8b945e19d2f217..ecade74c4d9850 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index eac3b3e3309a7a..03952391dbad11 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index 401daabd88b3a8..9a3bbd297ed9b7 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index 26fcb53c1748ef..8ecac5821b8d7c 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index c472d1f1bdb8ed..7f77615f09a8f0 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index 0b792166ad21c8..02190e2aac699e 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index 2e46b1e309c71b..dac4c65101db2b 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index c843c94b810d6c..5d95f72358409a 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index 1e586ae70e6dcb..be9bcb20e4acae 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 98da1667f83fa4..3a2e1d8eb48553 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index a61d79d28324a3..3b4dc8c8dbe191 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_cancellable_search.mdx b/api_docs/kbn_ml_cancellable_search.mdx index ecc3dad8006ecb..7fda32a6202b64 100644 --- a/api_docs/kbn_ml_cancellable_search.mdx +++ b/api_docs/kbn_ml_cancellable_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-cancellable-search title: "@kbn/ml-cancellable-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-cancellable-search plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-cancellable-search'] --- import kbnMlCancellableSearchObj from './kbn_ml_cancellable_search.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index a68a71c184587f..bddad4be53cfec 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index c94664fbafc4d2..44c318ad0633a7 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index fa07ca5a417eea..899f0313c8a100 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index b10d3d0bb47842..e664eaa61d4240 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 1a0d4f5d4a6249..cebdf85867838a 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 6c39004ba31765..f75310c36f61f9 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index 1386e21d31145c..510e1542d0f119 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index a69b15aa350ac7..ec6dec9b9d60c9 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index 8999d750385b26..bd53464f3382e9 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 8ce60cf630e636..3739aefe3f9d3f 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index c6d06a9dee3f98..040eecbaf53254 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index 246c04e6943492..63e5c5d6286ec2 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index a9af04a4754f63..3bb1ec9642670f 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index 92bab8559e488f..815921c27fdfd1 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index 6a9d2d38db29f1..8c6dc446dafbde 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index 12193ee482a7ef..7733cd5ed15720 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index 60ed40886ff085..008b2619d5bd90 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index 4734419d552ed9..9d976957fa6938 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 463203ab23a438..1b45e8ff581a6f 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_time_buckets.mdx b/api_docs/kbn_ml_time_buckets.mdx index 35808f41675f51..9bed3e7d98e82d 100644 --- a/api_docs/kbn_ml_time_buckets.mdx +++ b/api_docs/kbn_ml_time_buckets.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-time-buckets title: "@kbn/ml-time-buckets" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-time-buckets plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-time-buckets'] --- import kbnMlTimeBucketsObj from './kbn_ml_time_buckets.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index f2a33bf0de233b..9f171d79b9144c 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_ui_actions.mdx b/api_docs/kbn_ml_ui_actions.mdx index 907bc0bd4f38e2..11c518e24b374f 100644 --- a/api_docs/kbn_ml_ui_actions.mdx +++ b/api_docs/kbn_ml_ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-ui-actions title: "@kbn/ml-ui-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-ui-actions plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-ui-actions'] --- import kbnMlUiActionsObj from './kbn_ml_ui_actions.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index d8ab676dee534e..d2cda31264ab91 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_mock_idp_utils.mdx b/api_docs/kbn_mock_idp_utils.mdx index f577f22db4f025..4a35bdacaf30cb 100644 --- a/api_docs/kbn_mock_idp_utils.mdx +++ b/api_docs/kbn_mock_idp_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mock-idp-utils title: "@kbn/mock-idp-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mock-idp-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mock-idp-utils'] --- import kbnMockIdpUtilsObj from './kbn_mock_idp_utils.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index c987583cd42167..3c3e4138c779fd 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index 3b8dc07950acd8..9992ebe20caaa8 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index 930f5e7a79d5cf..1dc5321bcf6971 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 26d0629c305634..f6153a9f6c1f9c 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx index 046c132f8d36b3..7f3e670bbeea49 100644 --- a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-get-padded-alert-time-range-util title: "@kbn/observability-get-padded-alert-time-range-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-get-padded-alert-time-range-util plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-get-padded-alert-time-range-util'] --- import kbnObservabilityGetPaddedAlertTimeRangeUtilObj from './kbn_observability_get_padded_alert_time_range_util.devdocs.json'; diff --git a/api_docs/kbn_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx index ca2efb80448eb9..88d28ea4a83c00 100644 --- a/api_docs/kbn_openapi_bundler.mdx +++ b/api_docs/kbn_openapi_bundler.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-bundler title: "@kbn/openapi-bundler" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-bundler plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-bundler'] --- import kbnOpenapiBundlerObj from './kbn_openapi_bundler.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index 04804a93f6d149..418286506e3b36 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 46f985c62a3a7e..c3473550ecdfef 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index 60f1a092e29901..c57daa10853f1b 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_osquery_io_ts_types.mdx b/api_docs/kbn_osquery_io_ts_types.mdx index f43913a1fbb35e..6e1598dfce37b6 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx index 78af9b7fd01295..509330b3de5dc1 100644 --- a/api_docs/kbn_panel_loader.mdx +++ b/api_docs/kbn_panel_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-panel-loader title: "@kbn/panel-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/panel-loader plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/panel-loader'] --- import kbnPanelLoaderObj from './kbn_panel_loader.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 14f653398b46f0..3033ba99f1bf13 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_check.mdx b/api_docs/kbn_plugin_check.mdx index bfba51d448dd5a..ea93f44e2c8cf7 100644 --- a/api_docs/kbn_plugin_check.mdx +++ b/api_docs/kbn_plugin_check.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-check title: "@kbn/plugin-check" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-check plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-check'] --- import kbnPluginCheckObj from './kbn_plugin_check.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index aded1d2975df32..52b89d3991c208 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index 65aae400bcb522..ccfb2e0a5ffe91 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_presentation_containers.mdx b/api_docs/kbn_presentation_containers.mdx index cef167f6bd96a4..c5fbf9f7dd1a5a 100644 --- a/api_docs/kbn_presentation_containers.mdx +++ b/api_docs/kbn_presentation_containers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-containers title: "@kbn/presentation-containers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-containers plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index fac38a2bf32615..57d89d52805003 100644 --- a/api_docs/kbn_presentation_publishing.mdx +++ b/api_docs/kbn_presentation_publishing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-publishing title: "@kbn/presentation-publishing" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-publishing plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 8d8f2021a29a31..98d3a528777500 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 7f7798e3581876..8422a3507cb455 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 8b3a084c459744..939d4a77803906 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_hooks.mdx b/api_docs/kbn_react_hooks.mdx index 86308b7fb03fc6..b523cd4752ee59 100644 --- a/api_docs/kbn_react_hooks.mdx +++ b/api_docs/kbn_react_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-hooks title: "@kbn/react-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-hooks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-hooks'] --- import kbnReactHooksObj from './kbn_react_hooks.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index 6d272e28acc6ba..3d5d27ff2e549c 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index 83fb9ae258f820..f581c1b14ca093 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index dce6bdeda28226..3b2494976f6aab 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index 30ed94af5bdb67..29999416ca2c6e 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index 769255847c894b..c52481c92a2fad 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index 9dc3b1a44d26e9..a0347314f87514 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 0ab37f0d322807..77e725cfae3fa8 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index 6c25f131a4518a..aa0bd6217293f3 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index 9ee8a9b992cd69..d6a38392579e9e 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 3c13cb01ec5d95..f017da06d9281e 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 02c8eb873e0c25..14bafe45835dc7 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_csv_share_panel.mdx b/api_docs/kbn_reporting_csv_share_panel.mdx index 30cfd9d86286c2..037f4030f520af 100644 --- a/api_docs/kbn_reporting_csv_share_panel.mdx +++ b/api_docs/kbn_reporting_csv_share_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-csv-share-panel title: "@kbn/reporting-csv-share-panel" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-csv-share-panel plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-csv-share-panel'] --- import kbnReportingCsvSharePanelObj from './kbn_reporting_csv_share_panel.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index 8a6e1944356321..4e6da9fa82d13d 100644 --- a/api_docs/kbn_reporting_export_types_csv.mdx +++ b/api_docs/kbn_reporting_export_types_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv title: "@kbn/reporting-export-types-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index 6a0532f7631dbc..954b82beae3f05 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.mdx +++ b/api_docs/kbn_reporting_export_types_csv_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv-common title: "@kbn/reporting-export-types-csv-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index 4f568d36c7515a..946ebba102d946 100644 --- a/api_docs/kbn_reporting_export_types_pdf.mdx +++ b/api_docs/kbn_reporting_export_types_pdf.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf title: "@kbn/reporting-export-types-pdf" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf'] --- import kbnReportingExportTypesPdfObj from './kbn_reporting_export_types_pdf.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf_common.mdx b/api_docs/kbn_reporting_export_types_pdf_common.mdx index e0048f04e496e8..bd28fcbcd60fff 100644 --- a/api_docs/kbn_reporting_export_types_pdf_common.mdx +++ b/api_docs/kbn_reporting_export_types_pdf_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf-common title: "@kbn/reporting-export-types-pdf-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf-common'] --- import kbnReportingExportTypesPdfCommonObj from './kbn_reporting_export_types_pdf_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png.mdx b/api_docs/kbn_reporting_export_types_png.mdx index da68c401e434a2..5a3d3485a84a30 100644 --- a/api_docs/kbn_reporting_export_types_png.mdx +++ b/api_docs/kbn_reporting_export_types_png.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png title: "@kbn/reporting-export-types-png" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png'] --- import kbnReportingExportTypesPngObj from './kbn_reporting_export_types_png.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png_common.mdx b/api_docs/kbn_reporting_export_types_png_common.mdx index 9118276f5d388c..21a561c316f91c 100644 --- a/api_docs/kbn_reporting_export_types_png_common.mdx +++ b/api_docs/kbn_reporting_export_types_png_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png-common title: "@kbn/reporting-export-types-png-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png-common'] --- import kbnReportingExportTypesPngCommonObj from './kbn_reporting_export_types_png_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_mocks_server.mdx b/api_docs/kbn_reporting_mocks_server.mdx index b8419571d4b422..502c9b53594fc7 100644 --- a/api_docs/kbn_reporting_mocks_server.mdx +++ b/api_docs/kbn_reporting_mocks_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-mocks-server title: "@kbn/reporting-mocks-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-mocks-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index 7422229fee6fc1..af997976254989 100644 --- a/api_docs/kbn_reporting_public.mdx +++ b/api_docs/kbn_reporting_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-public title: "@kbn/reporting-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-public plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index 8af5d2474d8734..0ed4f1d634e57c 100644 --- a/api_docs/kbn_reporting_server.mdx +++ b/api_docs/kbn_reporting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-server title: "@kbn/reporting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index 98d30c0e78bd2f..8f3ff9bd87637e 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_response_ops_feature_flag_service.mdx b/api_docs/kbn_response_ops_feature_flag_service.mdx index a97ffa2d7f31cd..538573427a564c 100644 --- a/api_docs/kbn_response_ops_feature_flag_service.mdx +++ b/api_docs/kbn_response_ops_feature_flag_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-feature-flag-service title: "@kbn/response-ops-feature-flag-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-feature-flag-service plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-feature-flag-service'] --- import kbnResponseOpsFeatureFlagServiceObj from './kbn_response_ops_feature_flag_service.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index 32b46c7cfce9bd..abf549f7879dee 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_router_to_openapispec.mdx b/api_docs/kbn_router_to_openapispec.mdx index 766dbc9de54697..189a6168162128 100644 --- a/api_docs/kbn_router_to_openapispec.mdx +++ b/api_docs/kbn_router_to_openapispec.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-to-openapispec title: "@kbn/router-to-openapispec" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-to-openapispec plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-to-openapispec'] --- import kbnRouterToOpenapispecObj from './kbn_router_to_openapispec.devdocs.json'; diff --git a/api_docs/kbn_router_utils.mdx b/api_docs/kbn_router_utils.mdx index 4e8dff0fd21637..d2bc968cce1129 100644 --- a/api_docs/kbn_router_utils.mdx +++ b/api_docs/kbn_router_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-utils title: "@kbn/router-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-utils'] --- import kbnRouterUtilsObj from './kbn_router_utils.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index c0678bbb387e7d..6753bb86d6d854 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index bf4b1a5e20ff25..7f70d045f06ee0 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index 2945765803a1ed..b68bf847f8b026 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index d43d0f5f7950c6..241233903437a6 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index 632f445a2e4cbd..61f576ccec4c45 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index 90ad4394d37ad5..c04430411fd4ee 100644 --- a/api_docs/kbn_search_errors.mdx +++ b/api_docs/kbn_search_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-errors title: "@kbn/search-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-errors plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-errors'] --- import kbnSearchErrorsObj from './kbn_search_errors.devdocs.json'; diff --git a/api_docs/kbn_search_index_documents.mdx b/api_docs/kbn_search_index_documents.mdx index 1500bfe3ac9cad..ee933ffadffc5a 100644 --- a/api_docs/kbn_search_index_documents.mdx +++ b/api_docs/kbn_search_index_documents.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-index-documents title: "@kbn/search-index-documents" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-index-documents plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-index-documents'] --- import kbnSearchIndexDocumentsObj from './kbn_search_index_documents.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 308e2605254774..a4911af523c9fd 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_search_types.mdx b/api_docs/kbn_search_types.mdx index 8e5c8573924acb..dacc0a63e4c55f 100644 --- a/api_docs/kbn_search_types.mdx +++ b/api_docs/kbn_search_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-types title: "@kbn/search-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_hardening.mdx b/api_docs/kbn_security_hardening.mdx index 1232bf4143835e..c1d99a522e9bc9 100644 --- a/api_docs/kbn_security_hardening.mdx +++ b/api_docs/kbn_security_hardening.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-hardening title: "@kbn/security-hardening" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-hardening plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-hardening'] --- import kbnSecurityHardeningObj from './kbn_security_hardening.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx index 98c21f7f70ece8..78ab45087fb488 100644 --- a/api_docs/kbn_security_plugin_types_common.mdx +++ b/api_docs/kbn_security_plugin_types_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-common title: "@kbn/security-plugin-types-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-common plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-common'] --- import kbnSecurityPluginTypesCommonObj from './kbn_security_plugin_types_common.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_public.mdx b/api_docs/kbn_security_plugin_types_public.mdx index 057fef5e5ef5d0..64ee1ad1bd6457 100644 --- a/api_docs/kbn_security_plugin_types_public.mdx +++ b/api_docs/kbn_security_plugin_types_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-public title: "@kbn/security-plugin-types-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-public plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.devdocs.json b/api_docs/kbn_security_plugin_types_server.devdocs.json index 2100c7e7f1beb1..15aea85d3b0598 100644 --- a/api_docs/kbn_security_plugin_types_server.devdocs.json +++ b/api_docs/kbn_security_plugin_types_server.devdocs.json @@ -3193,83 +3193,83 @@ }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/services/security/security.ts" + "path": "x-pack/plugins/fleet/server/services/api_keys/security.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/services/api_keys/transform_api_keys.ts" + "path": "x-pack/plugins/fleet/server/services/security/security.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/services/api_keys/security.ts" + "path": "x-pack/plugins/fleet/server/services/api_keys/transform_api_keys.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/setup/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/settings/index.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/setup/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/settings/index.ts" }, { "plugin": "cloudDefend", diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index c9087ea8023c57..7476a1f55a9f43 100644 --- a/api_docs/kbn_security_plugin_types_server.mdx +++ b/api_docs/kbn_security_plugin_types_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-server title: "@kbn/security-plugin-types-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-server plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] --- import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index 3a1d5e7369cb2c..1ec8908ff8655b 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index e841ca2c8f0bdf..f3762cab5063eb 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index ba1039d1dfd6fd..63f4a70fb155c4 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-side-nav'] --- import kbnSecuritySolutionSideNavObj from './kbn_security_solution_side_nav.devdocs.json'; diff --git a/api_docs/kbn_security_solution_storybook_config.mdx b/api_docs/kbn_security_solution_storybook_config.mdx index ae4b404ccef505..1d7460b5e9c071 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 10961d6963e23f..337f9ac61e761b 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index 4814ce044f782c..7737f3b2578f9a 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index 428eedbb2e8074..0e9c907dcd407c 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index c79ea89803b9d5..787dc2539f43f4 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index aa2e7bccc0247a..8693ad038c7fde 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 06c14f87a45ef9..da917f28d8f8fa 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index daeead88afc6ea..a72ea475312b40 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 71b579c0a0d706..07d7b4f7cc05b1 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 4fae5675a89452..843e91cd417389 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index fb3633c531750c..af215ed77ffa20 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 2d942f0a44056b..57d831ae429c54 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index bf16d9874b489c..63316808fdde3c 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index 88975150d101f3..28a03759317715 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index f2393772847ad4..d5b841b270615a 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 36f1312f61b596..f444befb87ea9c 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index 66b123bb07699c..825c6d54bda3cf 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index ebda0f1aa6172b..59e218ff76cb34 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index b5d552e4533605..aa80f0b9ec5734 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 9309e3c61b357a..811665eb47b51d 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index 3635ca2fe050ab..c60933aa55a3b8 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index 7af28b5703e550..79fd5ca3170ce7 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index 58f50eb9b4a658..3786cf44243be6 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index 95b1d080735967..f98f68069a3d11 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 4d68a8e795e2b6..9fa1a0a96fc5eb 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index 22ee70fb1002b9..86bb254e27ceef 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index c5e07279648518..d055e16990504a 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index e6e7eaf2bd78d5..f9430a3121623d 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 3488a9ea6bcb61..479d22cd7919b1 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 9511099b234870..f2f59187e78bd2 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 46591e962fe0c8..f7bcd8a674ca24 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index 5b2499326c9021..c8f79c0b8358e6 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index c998ff4165ee6f..a3f3cb94eb74ed 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index 167e09ffee9e17..6927e6aef13c55 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index b7c756a0313e63..b638794940fb2c 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index f27479e18f11f7..fe51f1707507a1 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index b36b15944c3b62..282088305558bc 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index 391ac024acb876..16d456a7c75b4a 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index 6c60d31e46ba60..b431671ab16b3e 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index cc371e6820af46..6c1c20a32139f0 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index 039adb8ece3bad..5b8d449359e9bc 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index 61d3c1988aadc7..f45045dcaffab9 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index 0c6b6b8f511940..1f2e3ff7d743a8 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index f6d2a25b7a6036..ce75751d7cb980 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index f958c0f56a69f9..c35451215f2303 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index 2579dadd0415dd..cf0a2a23e81ec4 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index a1329fa0de8386..7d7ecdc6922e87 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index 2ecba86c2473c0..f772e6004e16d2 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index 421cf76e284eec..5be2c91a22b83c 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index 3f64089023a614..887a31b40b2808 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index 979dbc82c219ea..7511487ba56bf7 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index a75d6664bc60e3..88c3b4d5eb75f6 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index 3f20ea78011090..0ce60fec248f9c 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index df30092cd1a33f..831e5bdba86525 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index e2d39ccd79c506..7740c3e4c160c2 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index 729864ab7ab7fd..13423d36e33c65 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index 52ab086a5f40fc..be82ba5e352dd4 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index 248c6457165843..a7bb6856b2dc55 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index a4454b8ed220de..6fc5f819983cf3 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index d1f2c0fe743e9c..e53ad09f41e055 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 5e1d0141386a43..6144fc2b154d37 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index f96409b7154f1b..638e6c72f0cea3 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index 52c275264fe93e..69068b73c4fb5a 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 2a4c3c6400fe2e..d2ece90392a850 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_tabbed_modal.mdx b/api_docs/kbn_shared_ux_tabbed_modal.mdx index 7c34954ad71ead..7d52676fbebc4c 100644 --- a/api_docs/kbn_shared_ux_tabbed_modal.mdx +++ b/api_docs/kbn_shared_ux_tabbed_modal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-tabbed-modal title: "@kbn/shared-ux-tabbed-modal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-tabbed-modal plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-tabbed-modal'] --- import kbnSharedUxTabbedModalObj from './kbn_shared_ux_tabbed_modal.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 6abe34b608bbe1..23ce9cf96a2a8a 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.devdocs.json b/api_docs/kbn_slo_schema.devdocs.json index 8acc3fb8c8aaca..5707fe5fd6e538 100644 --- a/api_docs/kbn_slo_schema.devdocs.json +++ b/api_docs/kbn_slo_schema.devdocs.json @@ -760,7 +760,7 @@ "label": "FetchHistoricalSummaryResponse", "description": [], "signature": [ - "{ sloId: string; instanceId: string; data: ({ date: string; } & { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; } & { summaryUpdatedAt?: string | null | undefined; })[]; }[]" + "{ sloId: string; instanceId: string; data: { date: string; status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }[]; }[]" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/fetch_historical_summary.ts", "deprecated": false, @@ -880,7 +880,7 @@ "label": "FindSLOParams", "description": [], "signature": [ - "{ filters?: string | undefined; kqlQuery?: string | undefined; page?: string | undefined; perPage?: string | undefined; sortBy?: \"status\" | \"error_budget_consumed\" | \"error_budget_remaining\" | \"sli_value\" | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; hideStale?: boolean | undefined; }" + "{ filters?: string | undefined; kqlQuery?: string | undefined; page?: string | undefined; perPage?: string | undefined; sortBy?: \"status\" | \"error_budget_consumed\" | \"error_budget_remaining\" | \"sli_value\" | \"burn_rate_5m\" | \"burn_rate_1h\" | \"burn_rate_1d\" | undefined; sortDirection?: \"asc\" | \"desc\" | undefined; hideStale?: boolean | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find.ts", "deprecated": false, @@ -895,7 +895,7 @@ "label": "FindSLOResponse", "description": [], "signature": [ - "{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"last_value\" | \"cardinality\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; })[]; }" + "{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"last_value\" | \"cardinality\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; })[]; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find.ts", "deprecated": false, @@ -993,7 +993,7 @@ "label": "GetSLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"last_value\" | \"cardinality\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"last_value\" | \"cardinality\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get.ts", "deprecated": false, @@ -1083,7 +1083,7 @@ "label": "HistoricalSummaryResponse", "description": [], "signature": [ - "{ date: string; } & { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; } & { summaryUpdatedAt?: string | null | undefined; }" + "{ date: string; status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/fetch_historical_summary.ts", "deprecated": false, @@ -1293,7 +1293,7 @@ "label": "SLOWithSummaryResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"last_value\" | \"cardinality\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"last_value\" | \"cardinality\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -3563,16 +3563,10 @@ "]>; data: ", "ArrayC", "<", - "IntersectionC", - "<[", "TypeC", "<{ date: ", "Type", - "; }>, ", - "IntersectionC", - "<[", - "TypeC", - "<{ status: ", + "; status: ", "UnionC", "<[", "LiteralC", @@ -3594,15 +3588,7 @@ "NumberC", "; isEstimated: ", "BooleanC", - "; }>; }>, ", - "PartialC", - "<{ summaryUpdatedAt: ", - "UnionC", - "<[", - "StringC", - ", ", - "NullC", - "]>; }>]>]>>; }>>" + "; }>; }>>; }>>" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/fetch_historical_summary.ts", "deprecated": false, @@ -5384,7 +5370,13 @@ "LiteralC", "<\"sli_value\">, ", "LiteralC", - "<\"status\">]>; sortDirection: ", + "<\"status\">, ", + "LiteralC", + "<\"burn_rate_5m\">, ", + "LiteralC", + "<\"burn_rate_1h\">, ", + "LiteralC", + "<\"burn_rate_1d\">]>; sortDirection: ", "UnionC", "<[", "LiteralC", @@ -6888,7 +6880,13 @@ "NumberC", "; isEstimated: ", "BooleanC", - "; }>; }>, ", + "; }>; fiveMinuteBurnRate: ", + "NumberC", + "; oneHourBurnRate: ", + "NumberC", + "; oneDayBurnRate: ", + "NumberC", + "; }>, ", "PartialC", "<{ summaryUpdatedAt: ", "UnionC", @@ -9998,7 +9996,13 @@ "NumberC", "; isEstimated: ", "BooleanC", - "; }>; }>, ", + "; }>; fiveMinuteBurnRate: ", + "NumberC", + "; oneHourBurnRate: ", + "NumberC", + "; oneDayBurnRate: ", + "NumberC", + "; }>, ", "PartialC", "<{ summaryUpdatedAt: ", "UnionC", @@ -10531,16 +10535,10 @@ "label": "historicalSummarySchema", "description": [], "signature": [ - "IntersectionC", - "<[", "TypeC", "<{ date: ", "Type", - "; }>, ", - "IntersectionC", - "<[", - "TypeC", - "<{ status: ", + "; status: ", "UnionC", "<[", "LiteralC", @@ -10562,15 +10560,7 @@ "NumberC", "; isEstimated: ", "BooleanC", - "; }>; }>, ", - "PartialC", - "<{ summaryUpdatedAt: ", - "UnionC", - "<[", - "StringC", - ", ", - "NullC", - "]>; }>]>]>" + "; }>; }>" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/fetch_historical_summary.ts", "deprecated": false, @@ -17608,7 +17598,13 @@ "NumberC", "; isEstimated: ", "BooleanC", - "; }>; }>, ", + "; }>; fiveMinuteBurnRate: ", + "NumberC", + "; oneHourBurnRate: ", + "NumberC", + "; oneDayBurnRate: ", + "NumberC", + "; }>, ", "PartialC", "<{ summaryUpdatedAt: ", "UnionC", @@ -17738,7 +17734,13 @@ "NumberC", "; isEstimated: ", "BooleanC", - "; }>; }>, ", + "; }>; fiveMinuteBurnRate: ", + "NumberC", + "; oneHourBurnRate: ", + "NumberC", + "; oneDayBurnRate: ", + "NumberC", + "; }>, ", "PartialC", "<{ summaryUpdatedAt: ", "UnionC", diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 01cd0aa5c092b6..3a7ba2b4f2f63e 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index cf7dd2955ee5c4..14d5c70653e932 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_predicates.mdx b/api_docs/kbn_sort_predicates.mdx index 9f7e481a4e92f9..2011280cc05057 100644 --- a/api_docs/kbn_sort_predicates.mdx +++ b/api_docs/kbn_sort_predicates.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-predicates title: "@kbn/sort-predicates" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-predicates plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-predicates'] --- import kbnSortPredicatesObj from './kbn_sort_predicates.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index c1e25e156c40c2..3cdbb6cb2c6598 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index c375dc911e6adb..9252cdc7046f5d 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index 0b3d79c530c5ec..cd1c35ec26988f 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 6ddba8dc26974b..d3d28173929727 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.devdocs.json b/api_docs/kbn_test.devdocs.json index 7f24cc4e8ca6f6..d3b0fa6729cbf1 100644 --- a/api_docs/kbn_test.devdocs.json +++ b/api_docs/kbn_test.devdocs.json @@ -1782,6 +1782,38 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.SamlSessionManager.getEmail", + "type": "Function", + "tags": [], + "label": "getEmail", + "description": [], + "signature": [ + "(role: string) => Promise" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.SamlSessionManager.getEmail.$1", + "type": "string", + "tags": [], + "label": "role", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/test", "id": "def-common.SamlSessionManager.getUserData", @@ -1790,7 +1822,9 @@ "label": "getUserData", "description": [], "signature": [ - "(role: string) => Promise<{ email: string; fullname: string; }>" + "(role: string) => Promise<", + "UserProfile", + ">" ], "path": "packages/kbn-test/src/auth/session_manager.ts", "deprecated": false, diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index c37657a4c6b4f7..4421b403401223 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 313 | 4 | 265 | 12 | +| 315 | 4 | 267 | 13 | ## Common diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index ff3549b2dbfa76..1788f6e0829da1 100644 --- a/api_docs/kbn_test_eui_helpers.mdx +++ b/api_docs/kbn_test_eui_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-eui-helpers title: "@kbn/test-eui-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-eui-helpers plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-eui-helpers'] --- import kbnTestEuiHelpersObj from './kbn_test_eui_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 4e448d4eb1a64e..16fb734220c896 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 571fa45648a6a0..38d549f82a90dd 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_text_based_editor.mdx b/api_docs/kbn_text_based_editor.mdx index a89e7fa45f8b4e..75e745709a74f4 100644 --- a/api_docs/kbn_text_based_editor.mdx +++ b/api_docs/kbn_text_based_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-text-based-editor title: "@kbn/text-based-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/text-based-editor plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/text-based-editor'] --- import kbnTextBasedEditorObj from './kbn_text_based_editor.devdocs.json'; diff --git a/api_docs/kbn_timerange.mdx b/api_docs/kbn_timerange.mdx index 461b70833eef43..2d097d5e75e74d 100644 --- a/api_docs/kbn_timerange.mdx +++ b/api_docs/kbn_timerange.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-timerange title: "@kbn/timerange" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/timerange plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/timerange'] --- import kbnTimerangeObj from './kbn_timerange.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 3ebf1520252bbf..9e716aecc945cf 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index 78669fbf897c65..5bdef7f4e25c69 100644 --- a/api_docs/kbn_triggers_actions_ui_types.mdx +++ b/api_docs/kbn_triggers_actions_ui_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-triggers-actions-ui-types title: "@kbn/triggers-actions-ui-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/triggers-actions-ui-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; diff --git a/api_docs/kbn_try_in_console.mdx b/api_docs/kbn_try_in_console.mdx index b49e4cd037a878..3c3e9e346edad2 100644 --- a/api_docs/kbn_try_in_console.mdx +++ b/api_docs/kbn_try_in_console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-try-in-console title: "@kbn/try-in-console" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/try-in-console plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/try-in-console'] --- import kbnTryInConsoleObj from './kbn_try_in_console.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index 9efd9400402da1..db8ccb63f12c8e 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index fb9ad77c72effd..8428e9a42bbd7d 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index 8addb8d57ed808..4acf3eb5e68ba5 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index babfa755367fcd..45443736b64cf4 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index cfe2d5adb12f6b..11c3a781902145 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index b25351326f1888..6470406f9b3cbf 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index e0d919234d3a62..0e904c901ade3e 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 35516a91b7ec08..0b3533175afd74 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index 3cde751797a546..3529addc442684 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_prompt.mdx b/api_docs/kbn_unsaved_changes_prompt.mdx index 566058b20edcd7..6877c9595ecd24 100644 --- a/api_docs/kbn_unsaved_changes_prompt.mdx +++ b/api_docs/kbn_unsaved_changes_prompt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-prompt title: "@kbn/unsaved-changes-prompt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-prompt plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-prompt'] --- import kbnUnsavedChangesPromptObj from './kbn_unsaved_changes_prompt.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 3e3adc7521fb9e..7aa3a96e564519 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 77b41c7eed6ab5..5149cf98e47f94 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index d7b59ac3f14ea1..5fe09a5bb7435d 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index a5081ef999d42c..d02ac34ef384fe 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index 3f2a12356443f1..3ad836e69f7ad8 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 6a624e6e06f1c3..7a12739a8a49bd 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_visualization_utils.mdx b/api_docs/kbn_visualization_utils.mdx index 6e91f481911fec..7adc25184d8ebd 100644 --- a/api_docs/kbn_visualization_utils.mdx +++ b/api_docs/kbn_visualization_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-utils title: "@kbn/visualization-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-utils'] --- import kbnVisualizationUtilsObj from './kbn_visualization_utils.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index 79644c810c2846..76384b88894adc 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 63153d9efd0dab..3912fb378253cd 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index 772acffc1bd284..21ca40473b28ef 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 0d662c99e6770f..68e7dc00956854 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index ba8d0979b80a51..a771d0a42ff2f3 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index 0d0a98f5a8ff3e..a7ed980f094eb0 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index c9ab77fb77b312..307f3dc924d143 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 82ca8dad4c6080..8d5aa484a4f291 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index e146a2fc37e133..91f753208affbf 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 1297b5e11f2e48..3553269ec96e9b 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 7b4f39b14b024d..05a287f91b1295 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index 2584222ce481d9..5dbd8b3e558aa7 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 418e51c4a6f1d8..ab66bbd113633c 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/logs_data_access.mdx b/api_docs/logs_data_access.mdx index 588514ebf3ef40..6f9539d43aac26 100644 --- a/api_docs/logs_data_access.mdx +++ b/api_docs/logs_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsDataAccess title: "logsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the logsDataAccess plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsDataAccess'] --- import logsDataAccessObj from './logs_data_access.devdocs.json'; diff --git a/api_docs/logs_explorer.mdx b/api_docs/logs_explorer.mdx index f631d3ee2e99b2..80e08ec4cf6f70 100644 --- a/api_docs/logs_explorer.mdx +++ b/api_docs/logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsExplorer title: "logsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logsExplorer plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsExplorer'] --- import logsExplorerObj from './logs_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 68cbc3e157e0a0..3f2e723b5579a5 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 2fc02980dd1010..ed2c0c3d95e7bf 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index acd7a2070f619a..d6f7a1d8cce9a6 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 99a119682fa7e7..11fbb4d97f7e7f 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index 8f48d1167fbbd4..c1e9164d209219 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 95a0187a6ad75d..3d83b78e1cf32a 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index 7832f4f2bf928c..0d1627d4941c81 100644 --- a/api_docs/mock_idp_plugin.mdx +++ b/api_docs/mock_idp_plugin.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mockIdpPlugin title: "mockIdpPlugin" image: https://source.unsplash.com/400x175/?github description: API docs for the mockIdpPlugin plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] --- import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index d51708b8f602fe..06c2e7e11e522d 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index d58b02a3c4b859..3f382a0a6f1a3a 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 5063e895781067..4fc030a3e77126 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index 05b055cb03bcb4..056c9b626c0ac2 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index 5a4e745dadc110..68e23117c862a4 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index df9e71af6dee57..acdbb39c7900e7 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 1a318291fa2a6a..eb76936ebe69db 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index 16b571077703ce..62922ef331bbf6 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index ef4215909beb94..2d72d3c5759265 100644 --- a/api_docs/observability_a_i_assistant_app.mdx +++ b/api_docs/observability_a_i_assistant_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistantApp title: "observabilityAIAssistantApp" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistantApp plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistantApp'] --- import observabilityAIAssistantAppObj from './observability_a_i_assistant_app.devdocs.json'; diff --git a/api_docs/observability_ai_assistant_management.mdx b/api_docs/observability_ai_assistant_management.mdx index 367e7aaef7d8f3..368830b966205e 100644 --- a/api_docs/observability_ai_assistant_management.mdx +++ b/api_docs/observability_ai_assistant_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAiAssistantManagement title: "observabilityAiAssistantManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAiAssistantManagement plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAiAssistantManagement'] --- import observabilityAiAssistantManagementObj from './observability_ai_assistant_management.devdocs.json'; diff --git a/api_docs/observability_logs_explorer.mdx b/api_docs/observability_logs_explorer.mdx index 190c448c2aa95e..509dc56ef16b80 100644 --- a/api_docs/observability_logs_explorer.mdx +++ b/api_docs/observability_logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogsExplorer title: "observabilityLogsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogsExplorer plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogsExplorer'] --- import observabilityLogsExplorerObj from './observability_logs_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 2e8d03245163e6..47b27382ed39fb 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 9cca2ad645a009..9a7f818c21a99f 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index d5eec5505e9347..2656666b957d77 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index 2396233c269695..31904a5a9443e7 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 4dfdaac6b4daf7..13c56f83dab908 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -21,7 +21,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 49116 | 239 | 37582 | 1873 | +| 49119 | 239 | 37584 | 1875 | ## Plugin Directory @@ -101,7 +101,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | 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. | 84 | 0 | 84 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 240 | 0 | 24 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Simple UI for managing files in Kibana | 2 | 0 | 2 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1337 | 5 | 1216 | 71 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1338 | 5 | 1216 | 72 | | ftrApis | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 72 | 0 | 14 | 5 | | globalSearchBar | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | @@ -717,7 +717,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 4 | 0 | 2 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 41 | 2 | 21 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 5 | 1 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 313 | 4 | 265 | 12 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 315 | 4 | 267 | 13 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 25 | 0 | 13 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 131 | 3 | 98 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index aa3f68aff77030..55e27dddad02f8 100644 --- a/api_docs/presentation_panel.mdx +++ b/api_docs/presentation_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationPanel title: "presentationPanel" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationPanel plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationPanel'] --- import presentationPanelObj from './presentation_panel.devdocs.json'; diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 91cb071ee35f88..0cbb54c1599bc3 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 761810531e4ae9..59843ba7bdd49c 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index 9947501c2f541f..5c2ba575a0824f 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 63ed8a745eb510..5dd63fc0897b04 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index 8e7bde64480b30..006a1a383fb191 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index 7647262c33927c..e82d752c9c7135 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index f2082ab5c66180..982b4f418e67b9 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index c2c281d589b172..cacdcf0747d1fe 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 2396e3cf847923..5fb36ebc0642e1 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index 9bacb651df27b6..df8d813489241b 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index ddc363e901346f..71d04fa6f6d061 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index 320061330ee651..0f855887386a8d 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index 474abc799ddabd..0e2007a50b8711 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/saved_search.mdx b/api_docs/saved_search.mdx index 5ece66b9e095e7..c65779a953eb0e 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedSearch'] --- import savedSearchObj from './saved_search.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 6dfc43ab84a759..6061c6ce60372f 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index ad19664649f124..41de4c90572e6b 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/search_connectors.mdx b/api_docs/search_connectors.mdx index d982c87ac98117..e27f2058a1a4db 100644 --- a/api_docs/search_connectors.mdx +++ b/api_docs/search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchConnectors title: "searchConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the searchConnectors plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './search_connectors.devdocs.json'; diff --git a/api_docs/search_inference_endpoints.mdx b/api_docs/search_inference_endpoints.mdx index a5f6b6a6f55296..7c617046a080e6 100644 --- a/api_docs/search_inference_endpoints.mdx +++ b/api_docs/search_inference_endpoints.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchInferenceEndpoints title: "searchInferenceEndpoints" image: https://source.unsplash.com/400x175/?github description: API docs for the searchInferenceEndpoints plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchInferenceEndpoints'] --- import searchInferenceEndpointsObj from './search_inference_endpoints.devdocs.json'; diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index 3ff93cc375d3a2..efc97cf266849c 100644 --- a/api_docs/search_notebooks.mdx +++ b/api_docs/search_notebooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchNotebooks title: "searchNotebooks" image: https://source.unsplash.com/400x175/?github description: API docs for the searchNotebooks plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNotebooks'] --- import searchNotebooksObj from './search_notebooks.devdocs.json'; diff --git a/api_docs/search_playground.mdx b/api_docs/search_playground.mdx index 3bb2207551defd..fd6257e783ef79 100644 --- a/api_docs/search_playground.mdx +++ b/api_docs/search_playground.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchPlayground title: "searchPlayground" image: https://source.unsplash.com/400x175/?github description: API docs for the searchPlayground plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.devdocs.json b/api_docs/security.devdocs.json index eddfbc9e2951a1..f43fe4bd96a095 100644 --- a/api_docs/security.devdocs.json +++ b/api_docs/security.devdocs.json @@ -5497,83 +5497,83 @@ }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/services/security/security.ts" + "path": "x-pack/plugins/fleet/server/services/api_keys/security.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/services/api_keys/transform_api_keys.ts" + "path": "x-pack/plugins/fleet/server/services/security/security.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/services/api_keys/security.ts" + "path": "x-pack/plugins/fleet/server/services/api_keys/transform_api_keys.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/epm/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/setup/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/settings/index.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/package_policy/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/setup/handlers.ts" }, { "plugin": "fleet", - "path": "x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts" + "path": "x-pack/plugins/fleet/server/routes/settings/index.ts" }, { "plugin": "cloudDefend", diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 7f48fc8e0146ec..d1327bb9f85f58 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index ff4abc085b2282..09fd66a8fa53ba 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index e0aa8b4333f062..da3e0b614f45bb 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index 2463a21b9e4dfe..4dfe48856ba188 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index 706096cf75fd31..2b167cbb92301d 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index fbf138978c19f5..0a361ed9f29d42 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index 158be33f61896c..e48d941822de49 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 2e0eaec6c1144e..dc8c512217b739 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index 63f66580020cce..65f4bf5340d47d 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index 6fd44e6aabc8ec..4615111556016b 100644 --- a/api_docs/slo.mdx +++ b/api_docs/slo.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/slo title: "slo" image: https://source.unsplash.com/400x175/?github description: API docs for the slo plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'slo'] --- import sloObj from './slo.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index b6828d11044bc4..895059ad9b0556 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 81284051cb42c8..e9f21582eff651 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index bb9a6d60814ec0..3737d2302fe6b0 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/stack_connectors.mdx b/api_docs/stack_connectors.mdx index 4e717680a744f0..6b67580e44db90 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 582c46c3246036..f49b7846ed0955 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 8b3662d2412284..178ea146c56bad 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 183abe90f1e60d..2a237ce79ed098 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index 97a61b6b9a25e2..c35b4097e77e89 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 0e4e3e8dbf435a..444de09aa6b4ad 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/text_based_languages.mdx b/api_docs/text_based_languages.mdx index 1e6081c3edbb04..2b06f627d6f2de 100644 --- a/api_docs/text_based_languages.mdx +++ b/api_docs/text_based_languages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/textBasedLanguages title: "textBasedLanguages" image: https://source.unsplash.com/400x175/?github description: API docs for the textBasedLanguages plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'textBasedLanguages'] --- import textBasedLanguagesObj from './text_based_languages.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index fc7f6e67de76c5..5b74a013694046 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 7e5416c976f5fa..bcb9dba7866d9a 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 72bffa7500a427..76563f3a7636ac 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 727a49320f781b..a82268cb54719c 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 4ed721b537c368..dc674fa70fdf79 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 78c09c4820ac9a..953b01ceadd394 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index e0af6eb5c893cc..d738743a9477ec 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 264716778d31f4..2454d26694b22b 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 813ec045cd9de6..6ddb906f1436ad 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 533fea4599ee8f..7d9046ef2e02b5 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index 77b17b0d50d2c4..35f9262187c034 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 819922fd4335f2..d15b383e344daa 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index d3e7e16b9f13b4..8d1371644bd4dc 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index 19c252a88673fd..aa257292348cd4 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index 8ff7f742ac4103..4c024378c51a52 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 5d859c8a16fdfa..984c1023796042 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 44bdad781d962a..de21d886b7c467 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index 3abc3594f7fff6..ee4144f629efe5 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index 64c76b9c5ee865..0cd01627505778 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 2c126e0d7461a7..59414d94e8ed86 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index f2b754d3f633a4..d9f9590acbe695 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index e0dff8da037530..30af10196561f4 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index c4c16340f64c2a..5c5f8367dc6b9c 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index 4499a267601de4..0ca9f2fe7118c1 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index a268fa4c22655b..1176ba240c38e5 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2024-06-17 +date: 2024-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From ef91afd9c1c31f6700e02af79b3f610ace4b109c Mon Sep 17 00:00:00 2001 From: Agustina Nahir Ruidiaz <61565784+agusruidiazgd@users.noreply.github.com> Date: Tue, 18 Jun 2024 08:49:27 +0200 Subject: [PATCH 008/123] issue-177204: show username when fullName is empty string (#186298) ## Summary We could find and edge case on ESS Custom User doing QA on the issue: https://github.com/elastic/kibana/issues/177204. When user's full name is an empty string (not undefined or null) the greeting message was not displaying. In this PR, we change the logic and display user's username whenever the user's fullName value is an empty string. Before: ![image](https://github.com/elastic/kibana/assets/61565784/9138a923-647c-4c6d-9300-340040545e55) How it looks now: ![image](https://github.com/elastic/kibana/assets/61565784/d451ed60-cdcf-41f1-a01a-12f5d0c4202a) ### **Checklist** - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios. --- .../onboarding/welcome_header/index.test.tsx | 10 ++++++++++ .../landing_page/onboarding/welcome_header/index.tsx | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/welcome_header/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/welcome_header/index.test.tsx index 0eaf44e9cc69cc..8939ffd1456cd1 100644 --- a/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/welcome_header/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/welcome_header/index.test.tsx @@ -42,6 +42,16 @@ describe('WelcomeHeaderComponent', () => { expect(titleElement).toBeInTheDocument(); }); + it('should render username when fullName is an empty string', () => { + const fullName = ''; + const username = 'jd'; + mockUseCurrentUser.mockReturnValue({ fullName, username }); + + const { getByText } = render(); + const titleElement = getByText(`Hi ${username}!`); + expect(titleElement).toBeInTheDocument(); + }); + it('should render username when fullName is not provided', () => { const username = 'jd'; mockUseCurrentUser.mockReturnValue({ username }); diff --git a/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/welcome_header/index.tsx b/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/welcome_header/index.tsx index 848eece5b243a0..f659f8a0a45998 100644 --- a/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/welcome_header/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/welcome_header/index.tsx @@ -24,7 +24,7 @@ const WelcomeHeaderComponent: React.FC<{ productTier?: ProductTier }> = ({ produ const userName = useCurrentUser(); // Full name could be null, user name should always exist - const name = userName?.fullName ?? userName?.username; + const name = userName?.fullName || userName?.username; const projectFeaturesUrl = useProjectFeaturesUrl(); From 8ad77f6df9cc29b2218ded53209f9e97c595d0ff Mon Sep 17 00:00:00 2001 From: Antonio Date: Tue, 18 Jun 2024 09:03:00 +0200 Subject: [PATCH 009/123] [ResponseOps][Cases] Fix `edit tags` flaky test (#186295) Fixes [#175655](https://github.com/elastic/kibana/issues/175655) ## Summary The other tests already tested the edit button so I changed the scope to look only for the `no tags` message. --- .../case_view/components/edit_tags.test.tsx | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/cases/public/components/case_view/components/edit_tags.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/edit_tags.test.tsx index 7ced679368434d..583d7599d14cbc 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/edit_tags.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/edit_tags.test.tsx @@ -25,8 +25,7 @@ const defaultProps: EditTagsProps = { tags: [], }; -// FLAKY: https://github.com/elastic/kibana/issues/175655 -describe.skip('EditTags ', () => { +describe('EditTags ', () => { let appMockRender: AppMockRenderer; const sampleTags = ['coke', 'pepsi']; @@ -43,18 +42,11 @@ describe.skip('EditTags ', () => { appMockRender = createAppMockRenderer(); }); - it('renders no tags, and then edit', async () => { + it('renders no tags message', async () => { appMockRender.render(); expect(await screen.findByTestId('no-tags')).toBeInTheDocument(); - - userEvent.click(await screen.findByTestId('tag-list-edit-button')); - - await waitFor(() => { - expect(screen.queryByTestId('no-tags')).not.toBeInTheDocument(); - }); - - expect(await screen.findByTestId('edit-tags')).toBeInTheDocument(); + expect(await screen.findByTestId('tag-list-edit-button')).toBeInTheDocument(); }); it('edit tag from options on submit', async () => { From d3b81237ee3138e7a62ae34c19f65109b751f0b3 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 18 Jun 2024 09:49:50 +0200 Subject: [PATCH 010/123] [ML] AIOps Log Rate Analysis: Fix text field selection (#186176) If we analyse all detected text fields, we might run into performance issues with the `categorize_text` aggregation. Until this is resolved, we will rely on a predefined white list of supported text fields, for now set to `message` and `error.message`. --- .../queries/__mocks__/field_caps_pgbench.ts | 10 ++++++++++ .../queries/fetch_index_info.ts | 8 +++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/x-pack/packages/ml/aiops_log_rate_analysis/queries/__mocks__/field_caps_pgbench.ts b/x-pack/packages/ml/aiops_log_rate_analysis/queries/__mocks__/field_caps_pgbench.ts index a4d85d8673971f..bc3aec796ebe62 100644 --- a/x-pack/packages/ml/aiops_log_rate_analysis/queries/__mocks__/field_caps_pgbench.ts +++ b/x-pack/packages/ml/aiops_log_rate_analysis/queries/__mocks__/field_caps_pgbench.ts @@ -8,6 +8,16 @@ export const fieldCapsPgBenchMock = { indices: ['.ds-filebeat-8.2.0-2022.06.07-000082'], fields: { + // The next two fields are not in the original field caps response, + // but are added here to test the logic to ignore fields that are not + // in the white list. It's based on a real world example where the mapping + // included a double mapping of text+integer. + ignore_this_text_field: { + text: { type: 'text', metadata_field: false, searchable: true, aggregatable: false }, + }, + 'ignore_this_text_field.int': { + integer: { type: 'integer', metadata_field: false, searchable: true, aggregatable: true }, + }, 'kubernetes.node.uid': { keyword: { type: 'keyword', metadata_field: false, searchable: true, aggregatable: true }, }, diff --git a/x-pack/packages/ml/aiops_log_rate_analysis/queries/fetch_index_info.ts b/x-pack/packages/ml/aiops_log_rate_analysis/queries/fetch_index_info.ts index 1bb5b701fdd17f..458fc630b50094 100644 --- a/x-pack/packages/ml/aiops_log_rate_analysis/queries/fetch_index_info.ts +++ b/x-pack/packages/ml/aiops_log_rate_analysis/queries/fetch_index_info.ts @@ -17,6 +17,12 @@ import { getTotalDocCountRequest } from './get_total_doc_count_request'; // TODO Consolidate with duplicate `fetchPValues` in // `x-pack/plugins/observability_solution/apm/server/routes/correlations/queries/fetch_duration_field_candidates.ts` +// Supported field names for text fields for log rate analysis. +// If we analyse all detected text fields, we might run into performance +// issues with the `categorize_text` aggregation. Until this is resolved, we +// rely on a predefined white list of supported text fields. +const TEXT_FIELD_WHITE_LIST = ['message', 'error.message']; + const SUPPORTED_ES_FIELD_TYPES = [ ES_FIELD_TYPES.KEYWORD, ES_FIELD_TYPES.IP, @@ -76,7 +82,7 @@ export const fetchIndexInfo = async ( acceptableFields.add(key); } - if (isTextField) { + if (isTextField && TEXT_FIELD_WHITE_LIST.includes(key)) { acceptableTextFields.add(key); } From 250c729087569cea009692ef2120fcee6842fed1 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 18 Jun 2024 10:07:07 +0200 Subject: [PATCH 011/123] [Discover][ES|QL] Reset selected fields when modifying the ES|QL query (#185997) - Closes https://github.com/elastic/kibana/issues/183961 ## Summary This PR updates the logic of resetting columns when modifying the ES|QL query. The previous implementation was added in https://github.com/elastic/kibana/pull/167492 and then changed in https://github.com/elastic/kibana/pull/177241. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: Stratoula Kalafateli Co-authored-by: Matthias Wilhelm --- .buildkite/ftr_configs.yml | 1 + .../main/hooks/use_esql_mode.test.tsx | 58 ++++- .../application/main/hooks/use_esql_mode.ts | 66 ++--- .../apps/discover/esql/_esql_columns.ts | 245 ++++++++++++++++++ .../discover/{group4 => esql}/_esql_view.ts | 0 test/functional/apps/discover/esql/config.ts | 18 ++ test/functional/apps/discover/esql/index.ts | 26 ++ test/functional/apps/discover/group4/index.ts | 1 - test/functional/firefox/discover.config.ts | 1 + 9 files changed, 383 insertions(+), 33 deletions(-) create mode 100644 test/functional/apps/discover/esql/_esql_columns.ts rename test/functional/apps/discover/{group4 => esql}/_esql_view.ts (100%) create mode 100644 test/functional/apps/discover/esql/config.ts create mode 100644 test/functional/apps/discover/esql/index.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index aea151baae3a1a..83ae94ada8d065 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -115,6 +115,7 @@ enabled: - test/functional/apps/discover/ccs_compatibility/config.ts - test/functional/apps/discover/classic/config.ts - test/functional/apps/discover/embeddable/config.ts + - test/functional/apps/discover/esql/config.ts - test/functional/apps/discover/group1/config.ts - test/functional/apps/discover/group2_data_grid1/config.ts - test/functional/apps/discover/group2_data_grid2/config.ts diff --git a/src/plugins/discover/public/application/main/hooks/use_esql_mode.test.tsx b/src/plugins/discover/public/application/main/hooks/use_esql_mode.test.tsx index 12109ea01a4224..5f6d35afe8434a 100644 --- a/src/plugins/discover/public/application/main/hooks/use_esql_mode.test.tsx +++ b/src/plugins/discover/public/application/main/hooks/use_esql_mode.test.tsx @@ -150,10 +150,11 @@ describe('useEsqlMode', () => { }); }); - test('changing an ES|QL query with same result columns should not change state when loading and finished', async () => { + test('changing an ES|QL query with same result columns but a different index pattern should change state when loading and finished', async () => { const { replaceUrlState, stateContainer } = renderHookWithContext(false); const documents$ = stateContainer.dataState.data$.documents$; stateContainer.dataState.data$.documents$.next(msgComplete); + replaceUrlState.mockReset(); documents$.next({ fetchStatus: FetchStatus.PARTIAL, @@ -166,7 +167,54 @@ describe('useEsqlMode', () => { ], query: { esql: 'from the-data-view-2' }, }); + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); + + await waitFor(() => { + expect(replaceUrlState).toHaveBeenCalledWith({ + columns: [], + }); + }); + }); + + test('changing a ES|QL query with no transformational commands should not change state when loading and finished if index pattern is the same', async () => { + const { replaceUrlState, stateContainer } = renderHookWithContext(false); + const documents$ = stateContainer.dataState.data$.documents$; + stateContainer.dataState.data$.documents$.next(msgComplete); + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(0)); + replaceUrlState.mockReset(); + + documents$.next({ + fetchStatus: FetchStatus.PARTIAL, + result: [ + { + id: '1', + raw: { field1: 1 }, + flattened: { field1: 1 }, + } as unknown as DataTableRecord, + ], + // non transformational command + query: { esql: 'from the-data-view-title | where field1 > 0' }, + }); await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(0)); + replaceUrlState.mockReset(); + + documents$.next({ + fetchStatus: FetchStatus.PARTIAL, + result: [ + { + id: '1', + raw: { field1: 1 }, + flattened: { field1: 1 }, + } as unknown as DataTableRecord, + ], + // non transformational command + query: { esql: 'from the-data-view-title2 | where field1 > 0' }, + }); + await waitFor(() => { + expect(replaceUrlState).toHaveBeenCalledWith({ + columns: [], + }); + }); }); test('only changing an ES|QL query with same result columns should not change columns', async () => { @@ -268,7 +316,13 @@ describe('useEsqlMode', () => { query: { esql: 'from the-data-view-title | keep field 1 | WHERE field1=1' }, }); - expect(replaceUrlState).toHaveBeenCalledTimes(0); + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); + await waitFor(() => { + expect(replaceUrlState).toHaveBeenCalledWith({ + columns: ['field1', 'field2'], + }); + }); + replaceUrlState.mockReset(); documents$.next({ fetchStatus: FetchStatus.PARTIAL, diff --git a/src/plugins/discover/public/application/main/hooks/use_esql_mode.ts b/src/plugins/discover/public/application/main/hooks/use_esql_mode.ts index 2f3c99763fb047..841badc11537c9 100644 --- a/src/plugins/discover/public/application/main/hooks/use_esql_mode.ts +++ b/src/plugins/discover/public/application/main/hooks/use_esql_mode.ts @@ -7,8 +7,8 @@ */ import { isEqual } from 'lodash'; -import { isOfAggregateQueryType, getAggregateQueryMode } from '@kbn/es-query'; -import { hasTransformationalCommand } from '@kbn/esql-utils'; +import { isOfAggregateQueryType } from '@kbn/es-query'; +import { hasTransformationalCommand, getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; import { useCallback, useEffect, useRef } from 'react'; import type { DataViewsContract } from '@kbn/data-views-plugin/public'; import { switchMap } from 'rxjs'; @@ -31,9 +31,9 @@ export function useEsqlMode({ }) { const prev = useRef<{ query: string; - columns: string[]; + recentlyUpdatedToColumns: string[]; }>({ - columns: [], + recentlyUpdatedToColumns: [], query: '', }); const initialFetch = useRef(true); @@ -43,9 +43,10 @@ export function useEsqlMode({ if (prev.current.query) { // cleanup when it's not an ES|QL query prev.current = { - columns: [], + recentlyUpdatedToColumns: [], query: '', }; + initialFetch.current = true; } }, []); @@ -57,55 +58,60 @@ export function useEsqlMode({ if (!query || next.fetchStatus === FetchStatus.ERROR) { return; } + const sendComplete = () => { stateContainer.dataState.data$.documents$.next({ ...next, fetchStatus: FetchStatus.COMPLETE, }); }; + const { viewMode } = stateContainer.appState.getState(); - let nextColumns: string[] = []; const isEsqlQuery = isOfAggregateQueryType(query); - const hasResults = Boolean(next.result?.length); - let queryHasTransformationalCommands = false; - if ('esql' in query) { - if (hasTransformationalCommand(query.esql)) { - queryHasTransformationalCommands = true; - } - } if (isEsqlQuery) { - const language = getAggregateQueryMode(query); + const hasResults = Boolean(next.result?.length); + if (next.fetchStatus !== FetchStatus.PARTIAL) { return; } + let nextColumns: string[] = prev.current.recentlyUpdatedToColumns; + if (hasResults) { - // check if state needs to contain column transformation due to a different columns in the resultset const firstRow = next.result![0]; - const firstRowColumns = Object.keys(firstRow.raw).slice(0, MAX_NUM_OF_COLUMNS); - if (!queryHasTransformationalCommands) { - nextColumns = []; - initialFetch.current = false; + const firstRowColumns = Object.keys(firstRow.raw); + + if (hasTransformationalCommand(query.esql)) { + nextColumns = firstRowColumns.slice(0, MAX_NUM_OF_COLUMNS); } else { - nextColumns = firstRowColumns; - if (initialFetch.current && !prev.current.columns.length) { - prev.current.columns = firstRowColumns; - } + nextColumns = []; } } - const addColumnsToState = !isEqual(nextColumns, prev.current.columns); - const queryChanged = query[language] !== prev.current.query; + + if (initialFetch.current) { + initialFetch.current = false; + prev.current.query = query.esql; + prev.current.recentlyUpdatedToColumns = nextColumns; + } + + const indexPatternChanged = + getIndexPatternFromESQLQuery(query.esql) !== + getIndexPatternFromESQLQuery(prev.current.query); + + const addColumnsToState = + indexPatternChanged || !isEqual(nextColumns, prev.current.recentlyUpdatedToColumns); + const changeViewMode = viewMode !== getValidViewMode({ viewMode, isEsqlMode: true }); - if (!queryChanged || (!addColumnsToState && !changeViewMode)) { + + if (!indexPatternChanged && !addColumnsToState && !changeViewMode) { sendComplete(); return; } - if (queryChanged) { - prev.current.query = query[language]; - prev.current.columns = nextColumns; - } + prev.current.query = query.esql; + prev.current.recentlyUpdatedToColumns = nextColumns; + // just change URL state if necessary if (addColumnsToState || changeViewMode) { const nextState = { diff --git a/test/functional/apps/discover/esql/_esql_columns.ts b/test/functional/apps/discover/esql/_esql_columns.ts new file mode 100644 index 00000000000000..ba7f8447529abc --- /dev/null +++ b/test/functional/apps/discover/esql/_esql_columns.ts @@ -0,0 +1,245 @@ +/* + * 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 expect from '@kbn/expect'; + +import { FtrProviderContext } from '../ftr_provider_context'; + +const SAVED_SEARCH_NON_TRANSFORMATIONAL_INITIAL_COLUMNS = 'nonTransformationalInitialColumns'; +const SAVED_SEARCH_NON_TRANSFORMATIONAL_CUSTOM_COLUMNS = 'nonTransformationalCustomColumns'; +const SAVED_SEARCH_TRANSFORMATIONAL_INITIAL_COLUMNS = 'transformationalInitialColumns'; +const SAVED_SEARCH_TRANSFORMATIONAL_CUSTOM_COLUMNS = 'transformationalCustomColumns'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const security = getService('security'); + const dataGrid = getService('dataGrid'); + const browser = getService('browser'); + const monacoEditor = getService('monacoEditor'); + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects([ + 'common', + 'discover', + 'dashboard', + 'header', + 'timePicker', + 'unifiedFieldList', + ]); + + const defaultSettings = { + defaultIndex: 'logstash-*', + }; + + describe('discover esql columns', async function () { + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.uiSettings.replace(defaultSettings); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.discover.selectTextBaseLang(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + }); + + beforeEach(async () => { + await PageObjects.discover.clickNewSearchButton(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + }); + + it('should render initial columns for non-transformational commands correctly', async () => { + const columns = ['@timestamp', 'Document']; + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await browser.refresh(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await PageObjects.discover.saveSearch(SAVED_SEARCH_NON_TRANSFORMATIONAL_INITIAL_COLUMNS); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + }); + + it('should render custom columns for non-transformational commands correctly', async () => { + const columns = ['bytes', 'extension']; + await PageObjects.unifiedFieldList.clickFieldListItemAdd('bytes'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('extension'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await browser.refresh(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await PageObjects.discover.saveSearch(SAVED_SEARCH_NON_TRANSFORMATIONAL_CUSTOM_COLUMNS); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + }); + + it('should reset columns only if index pattern changes in non-transformational query', async () => { + const columns = ['@timestamp', 'Document']; + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await monacoEditor.setCodeEditorValue('from logstash-* | limit 1'); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await monacoEditor.setCodeEditorValue('from logs* | limit 1'); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await PageObjects.unifiedFieldList.clickFieldListItemAdd('bytes'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['bytes']); + + // different index pattern => reset columns + await monacoEditor.setCodeEditorValue('from logstash-* | limit 1'); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await PageObjects.unifiedFieldList.clickFieldListItemAdd('extension'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['extension']); + + // same index pattern => don't reset columns + await monacoEditor.setCodeEditorValue( + `${await monacoEditor.getCodeEditorValue()} | where bytes > 0` + ); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['extension']); + }); + + it('should render initial columns for a transformational command correctly', async () => { + const columns = ['ip', '@timestamp']; + await monacoEditor.setCodeEditorValue( + `${await monacoEditor.getCodeEditorValue()} | keep ip, @timestamp` + ); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await browser.refresh(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await PageObjects.discover.saveSearch(SAVED_SEARCH_TRANSFORMATIONAL_INITIAL_COLUMNS); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + }); + + it('should render custom columns for a transformational command correctly', async () => { + const columns = ['ip', 'bytes']; + await monacoEditor.setCodeEditorValue( + `${await monacoEditor.getCodeEditorValue()} | keep ip, @timestamp, bytes` + ); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['ip', '@timestamp', 'bytes']); + + await PageObjects.unifiedFieldList.clickFieldListItemRemove('@timestamp'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await browser.refresh(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + + await PageObjects.discover.saveSearch(SAVED_SEARCH_TRANSFORMATIONAL_CUSTOM_COLUMNS); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(columns); + }); + + it('should reset columns if available fields or index pattern are different in transformational query', async () => { + await monacoEditor.setCodeEditorValue('from logstash-* | keep ip, @timestamp'); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['ip', '@timestamp']); + + // reset columns if available fields are different + await monacoEditor.setCodeEditorValue('from logstash-* | keep ip, @timestamp, bytes'); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['ip', '@timestamp', 'bytes']); + + // don't reset columns if available fields and index pattern are the same + await monacoEditor.setCodeEditorValue( + 'from logstash-* | keep ip, @timestamp, bytes | limit 1' + ); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['ip', '@timestamp', 'bytes']); + await PageObjects.unifiedFieldList.clickFieldListItemRemove('@timestamp'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['ip', 'bytes']); + + // reset columns if index pattern is different + await monacoEditor.setCodeEditorValue('from logs* | keep ip, @timestamp, bytes | limit 1'); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['ip', '@timestamp', 'bytes']); + }); + + it('should restore columns correctly when switching between saved searches', async () => { + await PageObjects.discover.loadSavedSearch(SAVED_SEARCH_NON_TRANSFORMATIONAL_INITIAL_COLUMNS); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'Document']); + + await PageObjects.discover.loadSavedSearch(SAVED_SEARCH_NON_TRANSFORMATIONAL_CUSTOM_COLUMNS); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['bytes', 'extension']); + + await PageObjects.discover.loadSavedSearch(SAVED_SEARCH_TRANSFORMATIONAL_INITIAL_COLUMNS); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['ip', '@timestamp']); + + await PageObjects.discover.loadSavedSearch(SAVED_SEARCH_TRANSFORMATIONAL_CUSTOM_COLUMNS); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['ip', 'bytes']); + + await PageObjects.discover.clickNewSearchButton(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'Document']); + }); + }); +} diff --git a/test/functional/apps/discover/group4/_esql_view.ts b/test/functional/apps/discover/esql/_esql_view.ts similarity index 100% rename from test/functional/apps/discover/group4/_esql_view.ts rename to test/functional/apps/discover/esql/_esql_view.ts diff --git a/test/functional/apps/discover/esql/config.ts b/test/functional/apps/discover/esql/config.ts new file mode 100644 index 00000000000000..a70a190ca63f81 --- /dev/null +++ b/test/functional/apps/discover/esql/config.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 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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/test/functional/apps/discover/esql/index.ts b/test/functional/apps/discover/esql/index.ts new file mode 100644 index 00000000000000..5ba21ac0a8aa23 --- /dev/null +++ b/test/functional/apps/discover/esql/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/esql', function () { + before(async function () { + await browser.setWindowSize(1600, 1200); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_esql_columns')); + loadTestFile(require.resolve('./_esql_view')); + }); +} diff --git a/test/functional/apps/discover/group4/index.ts b/test/functional/apps/discover/group4/index.ts index 211b4501ed329c..bb685ce8cbe6b5 100644 --- a/test/functional/apps/discover/group4/index.ts +++ b/test/functional/apps/discover/group4/index.ts @@ -22,7 +22,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_discover_fields_api')); loadTestFile(require.resolve('./_adhoc_data_views')); - loadTestFile(require.resolve('./_esql_view')); loadTestFile(require.resolve('./_date_nested')); loadTestFile(require.resolve('./_chart_hidden')); loadTestFile(require.resolve('./_context_encoded_url_params')); diff --git a/test/functional/firefox/discover.config.ts b/test/functional/firefox/discover.config.ts index 5c9f9c09397546..61ffcb9fd21bfe 100644 --- a/test/functional/firefox/discover.config.ts +++ b/test/functional/firefox/discover.config.ts @@ -18,6 +18,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { testFiles: [ require.resolve('../apps/discover/classic'), + require.resolve('../apps/discover/esql'), require.resolve('../apps/discover/group1'), require.resolve('../apps/discover/group2_data_grid1'), require.resolve('../apps/discover/group2_data_grid2'), From 202a774d466ed6a1dbbfe8bbb9fa7783bb6ff447 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Tue, 18 Jun 2024 10:26:10 +0200 Subject: [PATCH 012/123] [ES|QL] Editor supports integrations (#184716) ## Summary Supporting integrations in the editor using the native monaco suggestions system. ![meow](https://github.com/elastic/kibana/assets/17003240/0e72ebd0-c71e-4282-b444-6106feb3926c) This PR: - Uses a different icon for the simple indices, I didn't like the previous one - Adds support of integrations using the built in monaco api capabilities - The integrations have a different icon and a different indicator (Integrations vs Indices) - I am fetching the integrations from the api that was given to me. The api is hardcoded because is very difficult to get it from the fleet plugin, I asked from the team to move their constants in a package https://github.com/elastic/kibana/issues/186061 ### Checklist - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../src/autocomplete/autocomplete.test.ts | 42 +++++++++++++--- .../src/autocomplete/autocomplete.ts | 45 +++++++++++++++-- .../src/autocomplete/factories.ts | 24 ++++++--- .../src/autocomplete/helper.ts | 10 +++- .../src/shared/types.ts | 10 +++- packages/kbn-text-based-editor/src/helpers.ts | 49 +++++++++++++++++-- .../src/text_based_languages_editor.tsx | 5 +- 7 files changed, 159 insertions(+), 26 deletions(-) diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts index efff60c382d340..528e5f338b53e3 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts @@ -21,6 +21,16 @@ import { getParamAtPosition } from './helper'; import { nonNullable } from '../shared/helpers'; import { METADATA_FIELDS } from '../shared/constants'; +interface Integration { + name: string; + hidden: boolean; + title?: string; + dataStreams: Array<{ + name: string; + title?: string; + }>; +} + const triggerCharacters = [',', '(', '=', ' ']; const fields: Array<{ name: string; type: string; suggestedAs?: string }> = [ @@ -42,13 +52,10 @@ const fields: Array<{ name: string; type: string; suggestedAs?: string }> = [ { name: 'kubernetes.something.something', type: 'number' }, ]; -const indexes = ( - [] as Array<{ name: string; hidden: boolean; suggestedAs: string | undefined }> -).concat( +const indexes = ([] as Array<{ name: string; hidden: boolean; suggestedAs?: string }>).concat( ['a', 'index', 'otherIndex', '.secretIndex', 'my-index'].map((name) => ({ name, hidden: name.startsWith('.'), - suggestedAs: undefined, })), ['my-index[quoted]', 'my-index$', 'my_index{}'].map((name) => ({ name, @@ -56,6 +63,18 @@ const indexes = ( suggestedAs: `\`${name}\``, })) ); + +const integrations: Integration[] = ['nginx', 'k8s'].map((name) => ({ + name, + hidden: false, + title: `integration-${name}`, + dataStreams: [ + { + name: `${name}-1`, + title: `integration-${name}-1`, + }, + ], +})); const policies = [ { name: 'policy', @@ -347,9 +366,8 @@ describe('autocomplete', () => { }); describe('from', () => { - const suggestedIndexes = indexes - .filter(({ hidden }) => !hidden) - .map(({ name, suggestedAs }) => suggestedAs || name); + const suggestedIndexes = indexes.filter(({ hidden }) => !hidden).map(({ name }) => name); + // Monaco will filter further down here testSuggestions( 'f', @@ -372,6 +390,16 @@ describe('autocomplete', () => { METADATA_FIELDS.filter((field) => field !== '_index'), ' ' ); + + // with integrations support + const dataSources = indexes.concat(integrations); + const suggestedDataSources = dataSources + .filter(({ hidden }) => !hidden) + .map(({ name }) => name); + + testSuggestions('from ', suggestedDataSources, '', [undefined, dataSources, undefined]); + testSuggestions('from a,', suggestedDataSources, '', [undefined, dataSources, undefined]); + testSuggestions('from *,', suggestedDataSources, '', [undefined, dataSources, undefined]); }); describe('show', () => { diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index e753255624383b..ba2f180fb51f61 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -84,11 +84,19 @@ import { getFunctionsToIgnoreForStats, getParamAtPosition, getQueryForFields, + getSourcesFromCommands, isAggFunctionUsedAlready, } from './helper'; import { FunctionArgSignature } from '../definitions/types'; type GetSourceFn = () => Promise; +type GetDataSourceFn = (sourceName: string) => Promise< + | { + name: string; + dataStreams?: Array<{ name: string; title?: string }>; + } + | undefined +>; type GetFieldsByTypeFn = ( type: string | string[], ignored?: string[] @@ -203,6 +211,7 @@ export async function suggest( resourceRetriever ); const getSources = getSourcesRetriever(resourceRetriever); + const getDatastreamsForIntegration = getDatastreamsForIntegrationRetriever(resourceRetriever); const { getPolicies, getPolicyMetadata } = getPolicyRetriever(resourceRetriever); if (astContext.type === 'newCommand') { @@ -223,6 +232,7 @@ export async function suggest( ast, astContext, getSources, + getDatastreamsForIntegration, getFieldsByType, getFieldsMap, getPolicies, @@ -303,7 +313,21 @@ function getSourcesRetriever(resourceRetriever?: ESQLCallbacks) { return async () => { const list = (await helper()) || []; // hide indexes that start with . - return buildSourcesDefinitions(list.filter(({ hidden }) => !hidden).map(({ name }) => name)); + return buildSourcesDefinitions( + list + .filter(({ hidden }) => !hidden) + .map(({ name, dataStreams, title }) => { + return { name, isIntegration: Boolean(dataStreams && dataStreams.length), title }; + }) + ); + }; +} + +function getDatastreamsForIntegrationRetriever(resourceRetriever?: ESQLCallbacks) { + const helper = getSourcesHelper(resourceRetriever); + return async (sourceName: string) => { + const list = (await helper()) || []; + return list.find(({ name }) => name === sourceName); }; } @@ -475,6 +499,7 @@ async function getExpressionSuggestionsByType( node: ESQLSingleAstItem | undefined; }, getSources: GetSourceFn, + getDatastreamsForIntegration: GetDataSourceFn, getFieldsByType: GetFieldsByTypeFn, getFieldsMap: GetFieldsMapFn, getPolicies: GetPoliciesFn, @@ -829,9 +854,21 @@ async function getExpressionSuggestionsByType( const policies = await getPolicies(); suggestions.push(...(policies.length ? policies : [buildNoPoliciesAvailableDefinition()])); } else { - // FROM - // @TODO: filter down the suggestions here based on other existing sources defined - suggestions.push(...(await getSources())); + const index = getSourcesFromCommands(commands, 'index'); + // This is going to be empty for simple indices, and not empty for integrations + if (index && index.text) { + const source = index.text.replace(EDITOR_MARKER, ''); + const dataSource = await getDatastreamsForIntegration(source); + const newDefinitions = buildSourcesDefinitions( + dataSource?.dataStreams?.map(({ name }) => ({ name, isIntegration: false })) || [] + ); + suggestions.push(...newDefinitions); + } else { + // FROM + // @TODO: filter down the suggestions here based on other existing sources defined + const sourcesDefinitions = await getSources(); + suggestions.push(...sourcesDefinitions); + } } } } diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index 4b2e74729db78a..34c28b4b50d094 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -143,14 +143,22 @@ export const buildVariablesDefinitions = (variables: string[]): SuggestionRawDef sortText: 'D', })); -export const buildSourcesDefinitions = (sources: string[]): SuggestionRawDefinition[] => - sources.map((label) => ({ - label, - text: getSafeInsertText(label, { dashSupported: true }), - kind: 'Reference', - detail: i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.sourceDefinition', { - defaultMessage: `Index`, - }), +export const buildSourcesDefinitions = ( + sources: Array<{ name: string; isIntegration: boolean; title?: string }> +): SuggestionRawDefinition[] => + sources.map(({ name, isIntegration, title }) => ({ + label: title ?? name, + text: name, + isSnippet: isIntegration, + ...(isIntegration && { command: TRIGGER_SUGGESTION_COMMAND }), + kind: isIntegration ? 'Class' : 'Issue', + detail: isIntegration + ? i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.integrationDefinition', { + defaultMessage: `Integration`, + }) + : i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.sourceDefinition', { + defaultMessage: `Index`, + }), sortText: 'A', })); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts index 7bba3a5ab15eca..fa6e364c78ca9b 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { ESQLAstItem, ESQLCommand, ESQLFunction } from '@kbn/esql-ast'; +import type { ESQLAstItem, ESQLCommand, ESQLFunction, ESQLSource } from '@kbn/esql-ast'; import { FunctionDefinition } from '../definitions/types'; import { getFunctionDefinition, isAssignment, isFunctionItem } from '../shared/helpers'; @@ -63,3 +63,11 @@ export function getQueryForFields(queryString: string, commands: ESQLCommand[]) ? '' : queryString; } + +export function getSourcesFromCommands(commands: ESQLCommand[], sourceType: 'index' | 'policy') { + const fromCommand = commands.find(({ name }) => name === 'from'); + const args = (fromCommand?.args ?? []) as ESQLSource[]; + const sources = args.filter((arg) => arg.sourceType === sourceType); + + return sources.length === 1 ? sources[0] : undefined; +} diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/types.ts b/packages/kbn-esql-validation-autocomplete/src/shared/types.ts index 758218c52062fc..d2ce2e4b104df5 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/types.ts @@ -11,7 +11,15 @@ type CallbackFn = (ctx?: Options) => Result[] | P /** @public **/ export interface ESQLCallbacks { - getSources?: CallbackFn<{}, { name: string; hidden: boolean }>; + getSources?: CallbackFn< + {}, + { + name: string; + hidden: boolean; + title?: string; + dataStreams?: Array<{ name: string; title?: string }>; + } + >; getFieldsFor?: CallbackFn<{ query: string }, { name: string; type: string }>; getPolicies?: CallbackFn< {}, diff --git a/packages/kbn-text-based-editor/src/helpers.ts b/packages/kbn-text-based-editor/src/helpers.ts index 8d4943800f7507..59dffbd29e07f8 100644 --- a/packages/kbn-text-based-editor/src/helpers.ts +++ b/packages/kbn-text-based-editor/src/helpers.ts @@ -9,12 +9,27 @@ import { useRef } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; import { monaco } from '@kbn/monaco'; +import type { CoreStart } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { MapCache } from 'lodash'; export type MonacoMessage = monaco.editor.IMarkerData; +interface IntegrationsResponse { + items: Array<{ + name: string; + title?: string; + dataStreams: Array<{ + name: string; + title?: string; + }>; + }>; +} + +const INTEGRATIONS_API = '/api/fleet/epm/packages/installed'; +const API_VERSION = '2023-10-31'; + export const useDebounceWithOptions = ( fn: Function, { skipFirstRender }: { skipFirstRender: boolean } = { skipFirstRender: false }, @@ -227,10 +242,38 @@ export const clearCacheWhenOld = (cache: MapCache, esqlQuery: string) => { } }; -export const getESQLSources = async (dataViews: DataViewsPublicPluginStart) => { - const [remoteIndices, localIndices] = await Promise.all([ +const getIntegrations = async (core: CoreStart) => { + const fleetCapabilities = core.application.capabilities.fleet; + if (!fleetCapabilities?.read) { + return []; + } + // Ideally we should use the Fleet plugin constants to fetch the integrations + // import { EPM_API_ROUTES, API_VERSIONS } from '@kbn/fleet-plugin/common'; + // but it complicates things as we need to use an x-pack plugin as dependency to get 2 constants + // and this needs to be done in various places in the codebase which use the editor + // https://github.com/elastic/kibana/issues/186061 + const response = (await core.http + .get(INTEGRATIONS_API, { query: undefined, version: API_VERSION }) + .catch((error) => { + // eslint-disable-next-line no-console + console.error('Failed to fetch integrations', error); + })) as IntegrationsResponse; + + return ( + response?.items?.map((source) => ({ + name: source.name, + hidden: false, + title: source.title, + dataStreams: source.dataStreams, + })) ?? [] + ); +}; + +export const getESQLSources = async (dataViews: DataViewsPublicPluginStart, core: CoreStart) => { + const [remoteIndices, localIndices, integrations] = await Promise.all([ getRemoteIndicesList(dataViews), getIndicesList(dataViews), + getIntegrations(core), ]); - return [...localIndices, ...remoteIndices]; + return [...localIndices, ...remoteIndices, ...integrations]; }; diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index 686f508cdac1e5..b3729118f6e99d 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -391,7 +391,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ const { cache: dataSourcesCache, memoizedSources } = useMemo(() => { const fn = memoize( - (...args: [DataViewsPublicPluginStart]) => ({ + (...args: [DataViewsPublicPluginStart, CoreStart]) => ({ timestamp: Date.now(), result: getESQLSources(...args), }), @@ -405,7 +405,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ const callbacks: ESQLCallbacks = { getSources: async () => { clearCacheWhenOld(dataSourcesCache, queryString); - const sources = await memoizedSources(dataViews).result; + const sources = await memoizedSources(dataViews, core).result; return sources; }, getFieldsFor: async ({ query: queryToExecute }: { query?: string } | undefined = {}) => { @@ -445,6 +445,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ memoizedSources, dataSourcesCache, dataViews, + core, esqlFieldsCache, memoizedFieldsFromESQL, expressions, From 4f3e12e1502ae0ae8767a33876c2041d79021576 Mon Sep 17 00:00:00 2001 From: Bharat Pasupula <123897612+bhapas@users.noreply.github.com> Date: Tue, 18 Jun 2024 10:55:41 +0200 Subject: [PATCH 013/123] [Security GenAI][Integration Assistant] Fix bugs in ecs_mapping graph (#186301) ## Summary This PR holds multiple fixes for the `ecs_mapping` graph - Closes #185038 - Closes #185037 ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/graphs/ecs/prompts.ts | 11 ++-- .../server/graphs/ecs/validate.test.ts | 52 +++++++++++++++++++ .../server/graphs/ecs/validate.ts | 6 ++- 3 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/integration_assistant/server/graphs/ecs/validate.test.ts diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/prompts.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/prompts.ts index 56b985d2e0b7c9..f336b2cde4b481 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/prompts.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/prompts.ts @@ -30,11 +30,12 @@ Go through each value step by step and modify it with the following process: 3. If no relevant ECS field is found, the value should just be replaced with "null" rather than a new object. 4. Only if a relevant ECS field is found replace the value with a new object that has the keys "target", "confidence", "date_format" and "type". 5. The object key "target" should be set to be the full path of the ECS field name you think it matches. Set the object key "type" to be either "string", "boolean", "number" or "date" depending on what was detected as the example value. -6. If the type "date" is used, then set date_format to be an array of one or more of the equivilant JAVA date formats that fits the example value. If the type is not date then date_format should be set to an empty array []. -7. For each key that you set a target ECS field, also score the confidence you have in that the target field is correct, use a float between 0.0 and 1.0 and set the value in the nested "confidence" key. -8. When you want to use an ECS field as a value for a target, but another field already has the same ECS field as its target, try to find another fitting ECS field. If none is found then the one you are least confident about should have the object replaced with null. -9. If you are not confident for a specific field, you should always set the value to null. -10. These {package_name} log samples are based on source and destination type data, prioritize these compared to other related ECS fields like host.* and observer.*. +6. If the type "date" is used, then set date_format to be an array of one or more of the equivilant JAVA date formats that fits the example value, including those with nanosecond precision. If the type is not date then date_format should be set to an empty array []. +7. Use a custom date pattern if the built-in date format patterns do not match the example value , including those with nanosecond precision. +8. For each key that you set a target ECS field, also score the confidence you have in that the target field is correct, use a float between 0.0 and 1.0 and set the value in the nested "confidence" key. +9. When you want to use an ECS field as a value for a target, but another field already has the same ECS field as its target, try to find another fitting ECS field. If none is found then the one you are least confident about should have the object replaced with null. +10. If you are not confident for a specific field, you should always set the value to null. +11. These {package_name} log samples are based on source and destination type data, prioritize these compared to other related ECS fields like host.* and observer.*. You ALWAYS follow these guidelines when writing your response: diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.test.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.test.ts new file mode 100644 index 00000000000000..1fac2a93ce53ca --- /dev/null +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.test.ts @@ -0,0 +1,52 @@ +/* + * 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 { processMapping } from './validate'; + +describe('Testing ecs handler', () => { + it('processMapping()', async () => { + const path: string[] = []; + const value = { + checkpoint: { + firewall: { + product: null, + sequencenum: null, + subject: null, + ifdir: null, + origin: { + target: 'source.address', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + flags: null, + sendtotrackerasadvancedauditlog: null, + originsicname: null, + version: null, + administrator: { + target: 'user.name', + confidence: 0.8, + type: 'string', + date_formats: [], + }, + foo: { + target: null, // Invalid value , to be skipped + confidence: 0.8, + type: 'string', + date_formats: [], + }, + }, + }, + }; + const output: Record = {}; + await processMapping(path, value, output); + expect(output).toEqual({ + 'source.address': [['checkpoint', 'firewall', 'origin']], + 'user.name': [['checkpoint', 'firewall', 'administrator']], + }); + }); +}); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts index 0a01b1f59dcf35..15d3db7c955518 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts @@ -49,7 +49,11 @@ function findMissingFields(formattedSamples: string, ecsMapping: AnyObject): str return missingKeys; } -function processMapping(path: string[], value: any, output: Record): void { +export function processMapping( + path: string[], + value: any, + output: Record +): void { if (typeof value === 'object' && value !== null) { if (!Array.isArray(value)) { // If the value is a dict with all the keys returned for each source field, this is the full path of the field. From 3639308d37594c4c9631e0a8e079f2cff1b5de1c Mon Sep 17 00:00:00 2001 From: Jeramy Soucy Date: Tue, 18 Jun 2024 10:57:55 +0200 Subject: [PATCH 014/123] =?UTF-8?q?Upgrade=20micromatch@4.0.5=E2=86=924.0.?= =?UTF-8?q?7=20(#186064)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Upgrades the `micromatch` production dependency from v4.0.5 to v4.0.7. Also removes the `@langtrase/typescript-sdk` dependency, as it is not currently being referenced. --- package.json | 3 +- yarn.lock | 140 ++++++++------------------------------------------- 2 files changed, 23 insertions(+), 120 deletions(-) diff --git a/package.json b/package.json index 74d8629a2b1fa3..e8d694bb323e87 100644 --- a/package.json +++ b/package.json @@ -933,7 +933,6 @@ "@langchain/langgraph": "^0.0.23", "@langchain/openai": "^0.0.34", "@langtrase/trace-attributes": "^3.0.8", - "@langtrase/typescript-sdk": "^2.2.1", "@launchdarkly/node-server-sdk": "^9.4.5", "@loaders.gl/core": "^3.4.7", "@loaders.gl/json": "^3.4.7", @@ -1669,7 +1668,7 @@ "lmdb": "^2.9.2", "loader-utils": "^2.0.4", "marge": "^1.0.1", - "micromatch": "^4.0.5", + "micromatch": "^4.0.7", "mini-css-extract-plugin": "1.1.0", "minimist": "^1.2.6", "mocha": "^10.1.0", diff --git a/yarn.lock b/yarn.lock index 1481570519f4a3..abf9faf49c8ae1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6966,20 +6966,6 @@ dependencies: ncp "^2.0.0" -"@langtrase/typescript-sdk@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@langtrase/typescript-sdk/-/typescript-sdk-2.2.1.tgz#8ec60290b9882e161bc42bd51cf0a72396438633" - integrity sha512-CRzhOcGMLv68ICvENDBQ/PWIHyBNlc6lNBaqF9EM/s+HUusSPnBmvQ+nGObqpPR+uo7m9hDRRUmUXOlAooj0PQ== - dependencies: - "@langtrase/trace-attributes" "^3.0.8" - "@opentelemetry/api" "^1.7.0" - "@opentelemetry/instrumentation" "^0.49.1" - "@opentelemetry/sdk-trace-base" "^1.22.0" - "@opentelemetry/sdk-trace-node" "^1.22.0" - axios "^1.6.7" - node-loader "^2.0.0" - tiktoken "^1.0.13" - "@launchdarkly/js-sdk-common@2.5.0": version "2.5.0" resolved "https://registry.yarnpkg.com/@launchdarkly/js-sdk-common/-/js-sdk-common-2.5.0.tgz#d1dc595034bf6ee09b0313add5b8901fe9b82f26" @@ -7629,13 +7615,6 @@ dependencies: "@octokit/openapi-types" "^18.0.0" -"@opentelemetry/api-logs@0.49.1": - version "0.49.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.49.1.tgz#51a66ed5eb5eeeafffbd36c1713aa91cbfdd5259" - integrity sha512-kaNl/T7WzyMUQHQlVq7q0oV4Kev6+0xFwqzofryC66jgGMacd0QH5TwfpbUwSTby+SdAdprAe5UKMvBw4tKS5Q== - dependencies: - "@opentelemetry/api" "^1.0.0" - "@opentelemetry/api-metrics@0.31.0", "@opentelemetry/api-metrics@^0.31.0": version "0.31.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api-metrics/-/api-metrics-0.31.0.tgz#0ed4cf4d7c731f968721c2b303eaf5e9fd42f736" @@ -7643,16 +7622,11 @@ dependencies: "@opentelemetry/api" "^1.0.0" -"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.1.0", "@opentelemetry/api@^1.4.1", "@opentelemetry/api@^1.7.0": +"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.1.0", "@opentelemetry/api@^1.4.1": version "1.8.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.8.0.tgz#5aa7abb48f23f693068ed2999ae627d2f7d902ec" integrity sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w== -"@opentelemetry/context-async-hooks@1.24.0": - version "1.24.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-1.24.0.tgz#f5f8cc15038d293a8e9b570543c1f36aa4ee17ec" - integrity sha512-s7xaQ9ifDpJvwbWRLkZD/J5hY35w+MECm4TQUkg6szRcny9lf6oVhWij4w3JJFQgvHQMXU7oXOpX8Z05HxV/8g== - "@opentelemetry/core@1.15.0": version "1.15.0" resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.15.0.tgz#2ba928df0443732825a72a766c2edae9a7f9863f" @@ -7715,18 +7689,6 @@ "@opentelemetry/core" "1.5.0" "@opentelemetry/sdk-metrics-base" "0.31.0" -"@opentelemetry/instrumentation@^0.49.1": - version "0.49.1" - resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.49.1.tgz#1b95e5f9448a96e7af97e03846772829439a9a91" - integrity sha512-0DLtWtaIppuNNRRllSD4bjU8ZIiLp1cDXvJEbp752/Zf+y3gaLNaoGRGIlX4UHhcsrmtL+P2qxi3Hodi8VuKiQ== - dependencies: - "@opentelemetry/api-logs" "0.49.1" - "@types/shimmer" "^1.0.2" - import-in-the-middle "1.7.1" - require-in-the-middle "^7.1.1" - semver "^7.5.2" - shimmer "^1.2.1" - "@opentelemetry/otlp-exporter-base@0.34.0": version "0.34.0" resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.34.0.tgz#c6020b63590d4b8ac3833eda345a6f582fa014b1" @@ -7754,20 +7716,6 @@ "@opentelemetry/sdk-metrics" "1.8.0" "@opentelemetry/sdk-trace-base" "1.8.0" -"@opentelemetry/propagator-b3@1.24.0": - version "1.24.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-b3/-/propagator-b3-1.24.0.tgz#88a2ffede42ac6df7c409bacec0c9f9cc181bc13" - integrity sha512-7TMIDE4+NO5vnkor+zned42wqca+hmhW5gWKhmYjUHC5B5uojo1PvtmBrd7kigFu96XvL4ZUWVzibWRWIQ/++Q== - dependencies: - "@opentelemetry/core" "1.24.0" - -"@opentelemetry/propagator-jaeger@1.24.0": - version "1.24.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.24.0.tgz#e67fe6f8f2f1d74335909a7f7352d0761039ab79" - integrity sha512-r3MX3AmJiUeiWTXSDOdwBeaO+ahvWcFCpuKxmhhsH8Q8LqDnjhNd3krqBh4Qsq9wa0WhWtiQaDs/NOCWoMOlOw== - dependencies: - "@opentelemetry/core" "1.24.0" - "@opentelemetry/resources@1.15.0": version "1.15.0" resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.15.0.tgz#748a6ae9017636b8b30f5dee1fff3e166e51f63d" @@ -7830,15 +7778,6 @@ lodash.merge "^4.6.2" tslib "^2.3.1" -"@opentelemetry/sdk-trace-base@1.24.0", "@opentelemetry/sdk-trace-base@^1.22.0", "@opentelemetry/sdk-trace-base@^1.24.0": - version "1.24.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.24.0.tgz#e2de869e33fd224f6d9f39bafa4172074d1086c8" - integrity sha512-H9sLETZ4jw9UJ3totV8oM5R0m4CW0ZIOLfp4NV3g0CM8HD5zGZcaW88xqzWDgiYRpctFxd+WmHtGX/Upoa2vRg== - dependencies: - "@opentelemetry/core" "1.24.0" - "@opentelemetry/resources" "1.24.0" - "@opentelemetry/semantic-conventions" "1.24.0" - "@opentelemetry/sdk-trace-base@1.8.0": version "1.8.0" resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.8.0.tgz#70713aab90978a16dea188c8335209f857be7384" @@ -7848,17 +7787,14 @@ "@opentelemetry/resources" "1.8.0" "@opentelemetry/semantic-conventions" "1.8.0" -"@opentelemetry/sdk-trace-node@^1.22.0": +"@opentelemetry/sdk-trace-base@^1.24.0": version "1.24.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.24.0.tgz#34c56f092f98a16e0e045152c9a4baf50ed8dcee" - integrity sha512-QgByHmM9uloTpcYEEyW9YJEIMKHFSIM677RH9pJPWWwtM2NQFbEp/8HIJw80Ymtaz6cAxg1Kay1ByqIVzq3t5g== + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.24.0.tgz#e2de869e33fd224f6d9f39bafa4172074d1086c8" + integrity sha512-H9sLETZ4jw9UJ3totV8oM5R0m4CW0ZIOLfp4NV3g0CM8HD5zGZcaW88xqzWDgiYRpctFxd+WmHtGX/Upoa2vRg== dependencies: - "@opentelemetry/context-async-hooks" "1.24.0" "@opentelemetry/core" "1.24.0" - "@opentelemetry/propagator-b3" "1.24.0" - "@opentelemetry/propagator-jaeger" "1.24.0" - "@opentelemetry/sdk-trace-base" "1.24.0" - semver "^7.5.2" + "@opentelemetry/resources" "1.24.0" + "@opentelemetry/semantic-conventions" "1.24.0" "@opentelemetry/semantic-conventions@1.15.0": version "1.15.0" @@ -10961,11 +10897,6 @@ resolved "https://registry.yarnpkg.com/@types/set-value/-/set-value-2.0.0.tgz#63d386b103926dcf49b50e16e0f6dd49983046be" integrity sha512-k8dCJEC80F/mbsIOZ5Hj3YSzTVVVBwMdtP/M9Rtc2TM4F5etVd+2UG8QUiAUfbXm4fABedL2tBZnrBheY7UwpA== -"@types/shimmer@^1.0.2": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/shimmer/-/shimmer-1.0.5.tgz#491d8984d4510e550bfeb02d518791d7f59d2b88" - integrity sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww== - "@types/sinon@^7.0.13": version "7.0.13" resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.0.13.tgz#ca039c23a9e27ebea53e0901ef928ea2a1a6d313" @@ -13164,7 +13095,7 @@ brace@0.11.1, brace@^0.11.1: braces@^2.3.1: version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz" integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" @@ -13178,12 +13109,12 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" breadth-filter@^2.0.0: version "2.0.0" @@ -17757,10 +17688,10 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -19613,16 +19544,6 @@ import-fresh@^3.1.0, import-fresh@^3.2.1, import-fresh@^3.3.0: parent-module "^1.0.0" resolve-from "^4.0.0" -import-in-the-middle@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.7.1.tgz#3e111ff79c639d0bde459bd7ba29dd9fdf357364" - integrity sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg== - dependencies: - acorn "^8.8.2" - acorn-import-assertions "^1.9.0" - cjs-module-lexer "^1.2.2" - module-details-from-path "^1.0.3" - import-in-the-middle@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.8.0.tgz#c94d88d53701de9a248f9710b41f533e67f598a4" @@ -22827,7 +22748,7 @@ micromark@^2.11.3, micromark@~2.11.0, micromark@~2.11.3: micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" @@ -22844,12 +22765,12 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" miller-rabin@^4.0.0: @@ -23797,13 +23718,6 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-loader@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/node-loader/-/node-loader-2.0.0.tgz#9109a6d828703fd3e0aa03c1baec12a798071562" - integrity sha512-I5VN34NO4/5UYJaUBtkrODPWxbobrE4hgDqPrjB25yPkonFhCmZ146vTH+Zg417E9Iwoh1l/MbRs1apc5J295Q== - dependencies: - loader-utils "^2.0.0" - node-preload@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" @@ -28301,11 +28215,6 @@ shelljs@^0.8.5: interpret "^1.0.0" rechoir "^0.6.2" -shimmer@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - should-equal@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" @@ -29990,11 +29899,6 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.2.tgz#a862e018e3fb1ea2ec3fce5d55605cf57f247371" integrity sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E= -tiktoken@^1.0.13: - version "1.0.14" - resolved "https://registry.yarnpkg.com/tiktoken/-/tiktoken-1.0.14.tgz#1263821f4ba0a4ec71604db8608a3accd43001c9" - integrity sha512-g5zd5r/DoH8Kw0fiYbYpVhb6WO8BHO1unXqmBBWKwoT17HwSounnDtMDFUKm2Pko8U47sjQarOe+9aUrnqmmTg== - time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" From 3d09eaa6fc7f1065e5bb0356f952058b9750d271 Mon Sep 17 00:00:00 2001 From: elena-shostak <165678770+elena-shostak@users.noreply.github.com> Date: Tue, 18 Jun 2024 11:10:52 +0200 Subject: [PATCH 015/123] [Spaces] Passing default solution from cloud onboarding process (#185926) ## Summary Passing default solution from cloud onboarding process. 1. Renaming. Solution changes are not released yet, would be shipped with `8.15`, so it's fine to do it. - `search` -> `es` - `observability` -> `oblt` - Adjusted telemetry accordingly 2. Added `cloud` as optional dependency to `spaces` plugin to use `onboarding.defaultSolution` passed through setup contract. ### How to test 1. Set `xpack.cloud.onboarding.default_solution` to `es | oblt | security` 2. Check that default space was created with provided solution `GET kbn:/api/spaces/space/default` ### Checklist - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) __Fixes: https://github.com/elastic/kibana/issues/184999__ --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- docs/api/spaces-management/get.asciidoc | 2 +- docs/api/spaces-management/get_all.asciidoc | 2 +- docs/api/spaces-management/post.asciidoc | 2 +- docs/api/spaces-management/put.asciidoc | 2 +- src/plugins/navigation/public/plugin.test.ts | 4 +-- src/plugins/navigation/public/plugin.tsx | 16 ++++++------ x-pack/plugins/security/server/plugin.ts | 3 ++- .../plugins/spaces/common/types/space/v1.ts | 4 ++- x-pack/plugins/spaces/kibana.jsonc | 3 ++- .../create_default_space.test.ts | 25 ++++++++++++++++++ .../default_space/create_default_space.ts | 5 +++- .../default_space/default_space_service.ts | 5 +++- .../spaces/server/lib/space_schema.test.ts | 8 +++--- .../plugins/spaces/server/lib/space_schema.ts | 4 +-- x-pack/plugins/spaces/server/plugin.test.ts | 24 +++++++++++++++++ x-pack/plugins/spaces/server/plugin.ts | 3 +++ .../saved_objects/saved_objects_service.ts | 4 +-- .../spaces_client/spaces_client.test.ts | 26 +++++++++---------- .../spaces_usage_collector.ts | 6 ++--- x-pack/plugins/spaces/tsconfig.json | 1 + .../schema/xpack_plugins.json | 4 +-- .../common/suites/create.ts | 4 +-- .../spaces_only/telemetry/telemetry.ts | 6 ++--- 23 files changed, 113 insertions(+), 50 deletions(-) diff --git a/docs/api/spaces-management/get.asciidoc b/docs/api/spaces-management/get.asciidoc index d2dbeb0a3f4b40..f3e3462b2e0dae 100644 --- a/docs/api/spaces-management/get.asciidoc +++ b/docs/api/spaces-management/get.asciidoc @@ -32,6 +32,6 @@ The API returns the following: "initials": "MK", "disabledFeatures": [], "imageUrl": "", - "solution": "search" + "solution": "es" } -------------------------------------------------- diff --git a/docs/api/spaces-management/get_all.asciidoc b/docs/api/spaces-management/get_all.asciidoc index 0fd332c12b739e..92a65d670ad87d 100644 --- a/docs/api/spaces-management/get_all.asciidoc +++ b/docs/api/spaces-management/get_all.asciidoc @@ -72,7 +72,7 @@ The API returns the following: "initials": "MK", "disabledFeatures": ["discover"], "imageUrl": "", - "solution": "observability" + "solution": "oblt" } ] -------------------------------------------------- diff --git a/docs/api/spaces-management/post.asciidoc b/docs/api/spaces-management/post.asciidoc index b72d4df79c3d6a..4c5976249f80e8 100644 --- a/docs/api/spaces-management/post.asciidoc +++ b/docs/api/spaces-management/post.asciidoc @@ -37,7 +37,7 @@ experimental[] Create a {kib} space. For best results, your image should be 64x64. Images will not be optimized by this API call, so care should be taken when using custom images. `solution`:: - (Optional, string) The solution defined for the space. Can be one of `security`, `observability`, `search`, `classic` + (Optional, string) The solution defined for the space. Can be one of `security`, `oblt`, `es`, `classic` [[spaces-api-post-response-codes]] ==== Response codes diff --git a/docs/api/spaces-management/put.asciidoc b/docs/api/spaces-management/put.asciidoc index 0d1c8d5f2e7797..88d0d41114eb5b 100644 --- a/docs/api/spaces-management/put.asciidoc +++ b/docs/api/spaces-management/put.asciidoc @@ -37,7 +37,7 @@ experimental[] Update an existing {kib} space. For best results, your image should be 64x64. Images will not be optimized by this API call, so care should be taken when using custom images. `solution`:: - (Optional, string) The solution defined for the space. Can be one of `security`, `observability`, `search`, `classic`. + (Optional, string) The solution defined for the space. Can be one of `security`, `oblt`, `es`, `classic`. [[spaces-api-put-response-codes]] ==== Response codes diff --git a/src/plugins/navigation/public/plugin.test.ts b/src/plugins/navigation/public/plugin.test.ts index 19c104ebe52f25..6ebdfbe5003a2a 100644 --- a/src/plugins/navigation/public/plugin.test.ts +++ b/src/plugins/navigation/public/plugin.test.ts @@ -104,7 +104,7 @@ describe('Navigation Plugin', () => { spaces.getActiveSpace$ = jest .fn() - .mockReturnValue(of({ solution: 'search' } as Pick)); + .mockReturnValue(of({ solution: 'es' } as Pick)); plugin.start(coreStart, { unifiedSearch, cloud, cloudExperiments, spaces }); await new Promise((resolve) => setTimeout(resolve)); @@ -201,7 +201,7 @@ describe('Navigation Plugin', () => { featureOn: true, }); - for (const solution of ['search', 'observability', 'security']) { + for (const solution of ['es', 'oblt', 'security']) { spaces.getActiveSpace$ = jest .fn() .mockReturnValue(of({ solution } as Pick)); diff --git a/src/plugins/navigation/public/plugin.tsx b/src/plugins/navigation/public/plugin.tsx index 8c8ca5dec5b833..8aa9eea2351d6e 100644 --- a/src/plugins/navigation/public/plugin.tsx +++ b/src/plugins/navigation/public/plugin.tsx @@ -168,8 +168,12 @@ export class NavigationPublicPlugin activeSpace, }: { isFeatureEnabled: boolean; isServerless: boolean; activeSpace?: Space } ) { - const solutionView = serializeSpaceSolution(activeSpace); - const isProjectNav = isFeatureEnabled && Boolean(solutionView) && solutionView !== 'classic'; + const solutionView = activeSpace?.solution; + const isProjectNav = + isFeatureEnabled && + Boolean(solutionView) && + isKnownSolutionView(solutionView) && + solutionView !== 'classic'; // On serverless the chrome style is already set by the serverless plugin if (!isServerless) { @@ -182,10 +186,6 @@ export class NavigationPublicPlugin } } -function serializeSpaceSolution(space?: Space): 'classic' | 'es' | 'oblt' | 'security' | undefined { - if (!space) return undefined; - if (space.solution === 'search') return 'es'; - if (space.solution === 'observability') return 'oblt'; - if (space.solution === 'security') return 'security'; - return undefined; +function isKnownSolutionView(solution?: string) { + return solution && ['oblt', 'es', 'security'].includes(solution); } diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index 791d784c36a0de..cf362926bdd045 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -8,7 +8,7 @@ import type { Subscription } from 'rxjs'; import { map } from 'rxjs'; -import type { CloudStart } from '@kbn/cloud-plugin/server'; +import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/server'; import type { TypeOf } from '@kbn/config-schema'; import type { CoreSetup, @@ -88,6 +88,7 @@ export interface PluginSetupDependencies { taskManager: TaskManagerSetupContract; usageCollection?: UsageCollectionSetup; spaces?: SpacesPluginSetup; + cloud?: CloudSetup; } export interface PluginStartDependencies { diff --git a/x-pack/plugins/spaces/common/types/space/v1.ts b/x-pack/plugins/spaces/common/types/space/v1.ts index e18ad5e656efc6..9f110dc3098e35 100644 --- a/x-pack/plugins/spaces/common/types/space/v1.ts +++ b/x-pack/plugins/spaces/common/types/space/v1.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { OnBoardingDefaultSolution } from '@kbn/cloud-plugin/common'; + /** * A Space. */ @@ -62,7 +64,7 @@ export interface Space { /** * Solution selected for this space. */ - solution?: 'security' | 'observability' | 'search' | 'classic'; + solution?: OnBoardingDefaultSolution | 'classic'; } /** diff --git a/x-pack/plugins/spaces/kibana.jsonc b/x-pack/plugins/spaces/kibana.jsonc index e46747a401ea40..3b1555b52fcfd4 100644 --- a/x-pack/plugins/spaces/kibana.jsonc +++ b/x-pack/plugins/spaces/kibana.jsonc @@ -18,7 +18,8 @@ "optionalPlugins": [ "home", "management", - "usageCollection" + "usageCollection", + "cloud" ], "requiredBundles": [ "esUiShared", diff --git a/x-pack/plugins/spaces/server/default_space/create_default_space.test.ts b/x-pack/plugins/spaces/server/default_space/create_default_space.test.ts index e7a7b51b278d1a..7a401defe0aade 100644 --- a/x-pack/plugins/spaces/server/default_space/create_default_space.test.ts +++ b/x-pack/plugins/spaces/server/default_space/create_default_space.test.ts @@ -87,6 +87,31 @@ test(`it creates the default space when one does not exist`, async () => { ); }); +test(`it creates the default space when one does not exist with defined solution`, async () => { + const deps = createMockDeps({ + defaultExists: false, + }); + + await createDefaultSpace({ ...deps, solution: 'security' }); + + const repository = (await deps.getSavedObjects()).createInternalRepository(); + + expect(repository.get).toHaveBeenCalledTimes(1); + expect(repository.create).toHaveBeenCalledTimes(1); + expect(repository.create).toHaveBeenCalledWith( + 'space', + { + _reserved: true, + description: 'This is your default space!', + disabledFeatures: [], + name: 'Default', + color: '#00bfb3', + solution: 'security', + }, + { id: 'default' } + ); +}); + test(`it does not attempt to recreate the default space if it already exists`, async () => { const deps = createMockDeps({ defaultExists: true, diff --git a/x-pack/plugins/spaces/server/default_space/create_default_space.ts b/x-pack/plugins/spaces/server/default_space/create_default_space.ts index a7aee5a6d0ea1e..53658fd68a0f72 100644 --- a/x-pack/plugins/spaces/server/default_space/create_default_space.ts +++ b/x-pack/plugins/spaces/server/default_space/create_default_space.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { OnBoardingDefaultSolution } from '@kbn/cloud-plugin/common'; import type { Logger, SavedObjectsRepository, SavedObjectsServiceStart } from '@kbn/core/server'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; @@ -14,9 +15,10 @@ import { DEFAULT_SPACE_ID } from '../../common/constants'; interface Deps { getSavedObjects: () => Promise>; logger: Logger; + solution?: OnBoardingDefaultSolution; } -export async function createDefaultSpace({ getSavedObjects, logger }: Deps) { +export async function createDefaultSpace({ getSavedObjects, logger, solution }: Deps) { const { createInternalRepository } = await getSavedObjects(); const savedObjectsRepository = createInternalRepository(['space']); @@ -48,6 +50,7 @@ export async function createDefaultSpace({ getSavedObjects, logger }: Deps) { color: '#00bfb3', disabledFeatures: [], _reserved: true, + ...(solution ? { solution } : {}), }, options ); diff --git a/x-pack/plugins/spaces/server/default_space/default_space_service.ts b/x-pack/plugins/spaces/server/default_space/default_space_service.ts index d4c601369fde10..1faaf5490de896 100644 --- a/x-pack/plugins/spaces/server/default_space/default_space_service.ts +++ b/x-pack/plugins/spaces/server/default_space/default_space_service.ts @@ -19,6 +19,7 @@ import { timer, } from 'rxjs'; +import type { OnBoardingDefaultSolution } from '@kbn/cloud-plugin/common'; import type { CoreSetup, Logger, SavedObjectsServiceStart, ServiceStatus } from '@kbn/core/server'; import { ServiceStatusLevels } from '@kbn/core/server'; import type { ILicense } from '@kbn/licensing-plugin/server'; @@ -32,6 +33,7 @@ interface Deps { license$: Observable; spacesLicense: SpacesLicense; logger: Logger; + solution?: OnBoardingDefaultSolution; } export const RETRY_SCALE_DURATION = 100; @@ -64,7 +66,7 @@ export class DefaultSpaceService { private serviceStatus$?: BehaviorSubject; - public setup({ coreStatus, getSavedObjects, license$, spacesLicense, logger }: Deps) { + public setup({ coreStatus, getSavedObjects, license$, spacesLicense, logger, solution }: Deps) { const statusLogger = logger.get('status'); this.serviceStatus$ = new BehaviorSubject({ @@ -96,6 +98,7 @@ export class DefaultSpaceService { createDefaultSpace({ getSavedObjects, logger, + solution, }).then(() => { return { level: ServiceStatusLevels.available, diff --git a/x-pack/plugins/spaces/server/lib/space_schema.test.ts b/x-pack/plugins/spaces/server/lib/space_schema.test.ts index c31d7f5ca3c220..59795a6519dec1 100644 --- a/x-pack/plugins/spaces/server/lib/space_schema.test.ts +++ b/x-pack/plugins/spaces/server/lib/space_schema.test.ts @@ -238,7 +238,7 @@ describe('#imageUrl', () => { describe('#solution', () => { it('should throw error if solution is defined in serverless offering', () => { expect(() => - spaceServerlessSchema.validate({ ...defaultProperties, solution: 'search' }) + spaceServerlessSchema.validate({ ...defaultProperties, solution: 'es' }) ).toThrow(); }); @@ -253,13 +253,13 @@ describe('#solution', () => { .toThrowErrorMatchingInlineSnapshot(` "[solution]: types that failed validation: - [solution.0]: expected value to equal [security] - - [solution.1]: expected value to equal [observability] - - [solution.2]: expected value to equal [search] + - [solution.1]: expected value to equal [oblt] + - [solution.2]: expected value to equal [es] - [solution.3]: expected value to equal [classic]" `); expect(() => - spaceBaseSchema.validate({ ...defaultProperties, solution: ' search ' }, {}) + spaceBaseSchema.validate({ ...defaultProperties, solution: ' es ' }, {}) ).toThrow(); }); }); diff --git a/x-pack/plugins/spaces/server/lib/space_schema.ts b/x-pack/plugins/spaces/server/lib/space_schema.ts index cb184e322b5a94..f43ca3bc58f535 100644 --- a/x-pack/plugins/spaces/server/lib/space_schema.ts +++ b/x-pack/plugins/spaces/server/lib/space_schema.ts @@ -46,8 +46,8 @@ const spaceSchema = schema.object({ const solutionSchema = schema.oneOf([ schema.literal('security'), - schema.literal('observability'), - schema.literal('search'), + schema.literal('oblt'), + schema.literal('es'), schema.literal('classic'), ]); diff --git a/x-pack/plugins/spaces/server/plugin.test.ts b/x-pack/plugins/spaces/server/plugin.test.ts index 3ac505c6e2e9ab..b181b87e9cc94f 100644 --- a/x-pack/plugins/spaces/server/plugin.test.ts +++ b/x-pack/plugins/spaces/server/plugin.test.ts @@ -7,15 +7,20 @@ import { lastValueFrom } from 'rxjs'; +import { cloudMock } from '@kbn/cloud-plugin/public/mocks'; +import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { CoreSetup } from '@kbn/core/server'; import { coreMock } from '@kbn/core/server/mocks'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/server/mocks'; +import { createDefaultSpace } from './default_space/create_default_space'; import type { PluginsStart } from './plugin'; import { SpacesPlugin } from './plugin'; +jest.mock('./default_space/create_default_space'); + describe('Spaces plugin', () => { describe('#setup', () => { it('can setup with all optional plugins disabled, exposing the expected contract', () => { @@ -76,6 +81,25 @@ describe('Spaces plugin', () => { expect(usageCollection.getCollectorByType('spaces')).toBeDefined(); }); + + it('can setup space with default solution', async () => { + const initializerContext = coreMock.createPluginInitializerContext({ maxSpaces: 1000 }); + const core = coreMock.createSetup() as CoreSetup; + const features = featuresPluginMock.createSetup(); + const licensing = licensingMock.createSetup(); + const cloud = { + ...cloudMock.createSetup(), + apm: {}, + onboarding: { defaultSolution: 'security' }, + } as CloudSetup; + + const plugin = new SpacesPlugin(initializerContext); + plugin.setup(core, { features, licensing, cloud }); + + expect(createDefaultSpace).toHaveBeenCalledWith( + expect.objectContaining({ solution: 'security' }) + ); + }); }); describe('#start', () => { diff --git a/x-pack/plugins/spaces/server/plugin.ts b/x-pack/plugins/spaces/server/plugin.ts index a20396c3e46957..6ca6e27291f7d8 100644 --- a/x-pack/plugins/spaces/server/plugin.ts +++ b/x-pack/plugins/spaces/server/plugin.ts @@ -8,6 +8,7 @@ import type { Observable } from 'rxjs'; import { map } from 'rxjs'; +import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { CoreSetup, CoreStart, @@ -46,6 +47,7 @@ export interface PluginsSetup { licensing: LicensingPluginSetup; usageCollection?: UsageCollectionSetup; home?: HomeServerPluginSetup; + cloud?: CloudSetup; } export interface PluginsStart { @@ -161,6 +163,7 @@ export class SpacesPlugin license$: plugins.licensing.license$, spacesLicense: license, logger: this.log, + solution: plugins.cloud?.onboarding?.defaultSolution, }); initSpacesViewsRoutes({ diff --git a/x-pack/plugins/spaces/server/saved_objects/saved_objects_service.ts b/x-pack/plugins/spaces/server/saved_objects/saved_objects_service.ts index eb038d03e21aa3..ffa9ee7a8f5744 100644 --- a/x-pack/plugins/spaces/server/saved_objects/saved_objects_service.ts +++ b/x-pack/plugins/spaces/server/saved_objects/saved_objects_service.ts @@ -46,8 +46,8 @@ export class SpacesSavedObjectsService { solution: schema.maybe( schema.oneOf([ schema.literal('security'), - schema.literal('observability'), - schema.literal('search'), + schema.literal('oblt'), + schema.literal('es'), schema.literal('classic'), ]) ), diff --git a/x-pack/plugins/spaces/server/spaces_client/spaces_client.test.ts b/x-pack/plugins/spaces/server/spaces_client/spaces_client.test.ts index 600f6d1aa316cd..d9a23a3bc0c454 100644 --- a/x-pack/plugins/spaces/server/spaces_client/spaces_client.test.ts +++ b/x-pack/plugins/spaces/server/spaces_client/spaces_client.test.ts @@ -42,7 +42,7 @@ describe('#getAll', () => { imageUrl: 'go-bots/predates/transformers', disabledFeatures: [], _reserved: true, - solution: 'search', + solution: 'es', bar: 'foo-bar', // an extra attribute that will be ignored during conversion }, }, @@ -81,7 +81,7 @@ describe('#getAll', () => { initials: 'FB', imageUrl: 'go-bots/predates/transformers', disabledFeatures: [], - solution: 'search', + solution: 'es', _reserved: true, }, { @@ -224,7 +224,7 @@ describe('#get', () => { const mockCallWithRequestRepository = savedObjectsRepositoryMock.create(); mockCallWithRequestRepository.get.mockResolvedValue({ ...savedObject, - attributes: { ...(savedObject.attributes as Record), solution: 'search' }, + attributes: { ...(savedObject.attributes as Record), solution: 'es' }, }); const mockConfig = createMockConfig(); @@ -247,7 +247,7 @@ describe('#get', () => { const mockCallWithRequestRepository = savedObjectsRepositoryMock.create(); mockCallWithRequestRepository.get.mockResolvedValue({ ...savedObject, - attributes: { ...(savedObject.attributes as Record), solution: 'search' }, + attributes: { ...(savedObject.attributes as Record), solution: 'es' }, }); const mockConfig = createMockConfig(); @@ -261,7 +261,7 @@ describe('#get', () => { const id = savedObject.id; const actualSpace = await client.get(id); - expect(actualSpace).toEqual({ ...expectedSpace, solution: 'search' }); + expect(actualSpace).toEqual({ ...expectedSpace, solution: 'es' }); }); }); @@ -399,7 +399,7 @@ describe('#create', () => { ); await expect( - client.create({ ...spaceToCreate, solution: 'search' }) + client.create({ ...spaceToCreate, solution: 'es' }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to create Space, solution property is forbidden in serverless"` ); @@ -418,7 +418,7 @@ describe('#create', () => { const mockCallWithRequestRepository = savedObjectsRepositoryMock.create(); mockCallWithRequestRepository.create.mockResolvedValue({ ...savedObject, - attributes: { ...(savedObject.attributes as Record), solution: 'search' }, + attributes: { ...(savedObject.attributes as Record), solution: 'es' }, }); mockCallWithRequestRepository.find.mockResolvedValue({ total: maxSpaces - 1, @@ -438,9 +438,9 @@ describe('#create', () => { 'traditional' ); - const actualSpace = await client.create({ ...spaceToCreate, solution: 'search' }); + const actualSpace = await client.create({ ...spaceToCreate, solution: 'es' }); - expect(actualSpace).toEqual({ ...expectedReturnedSpace, solution: 'search' }); + expect(actualSpace).toEqual({ ...expectedReturnedSpace, solution: 'es' }); expect(mockCallWithRequestRepository.find).toHaveBeenCalledWith({ type: 'space', @@ -449,7 +449,7 @@ describe('#create', () => { }); expect(mockCallWithRequestRepository.create).toHaveBeenCalledWith( 'space', - { ...attributes, solution: 'search' }, + { ...attributes, solution: 'es' }, { id, } @@ -609,7 +609,7 @@ describe('#update', () => { ); await expect( - client.update(id, { ...spaceToUpdate, solution: 'search' }) + client.update(id, { ...spaceToUpdate, solution: 'es' }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to update Space, solution property is forbidden in serverless"` ); @@ -659,11 +659,11 @@ describe('#update', () => { 'traditional' ); const id = savedObject.id; - await client.update(id, { ...spaceToUpdate, solution: 'search' }); + await client.update(id, { ...spaceToUpdate, solution: 'es' }); expect(mockCallWithRequestRepository.update).toHaveBeenCalledWith('space', id, { ...attributes, - solution: 'search', + solution: 'es', }); expect(mockCallWithRequestRepository.get).toHaveBeenCalledWith('space', id); }); diff --git a/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts b/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts index 16b5ca1a1e9f09..d222c21fc72bea 100644 --- a/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts +++ b/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts @@ -46,7 +46,7 @@ async function getSpacesUsage( } const knownFeatureIds = features.getKibanaFeatures().map((feature) => feature.id); - const knownSolutions = ['classic', 'search', 'observability', 'security', 'unset']; + const knownSolutions = ['classic', 'es', 'oblt', 'security', 'unset']; const resp = (await esClient.search({ index: kibanaIndex, @@ -205,13 +205,13 @@ export function getSpacesUsageCollector( description: 'The number of spaces which have solution set to classic.', }, }, - search: { + es: { type: 'long', _meta: { description: 'The number of spaces which have solution set to search.', }, }, - observability: { + oblt: { type: 'long', _meta: { description: 'The number of spaces which have solution set to observability.', diff --git a/x-pack/plugins/spaces/tsconfig.json b/x-pack/plugins/spaces/tsconfig.json index 048004ff11334b..b0da959cc57ea1 100644 --- a/x-pack/plugins/spaces/tsconfig.json +++ b/x-pack/plugins/spaces/tsconfig.json @@ -36,6 +36,7 @@ "@kbn/react-kibana-context-render", "@kbn/utility-types-jest", "@kbn/security-plugin-types-public", + "@kbn/cloud-plugin", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index b63d1f52b37a3e..a42825ed281f61 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -15121,13 +15121,13 @@ "description": "The number of spaces which have solution set to classic." } }, - "search": { + "es": { "type": "long", "_meta": { "description": "The number of spaces which have solution set to search." } }, - "observability": { + "oblt": { "type": "long", "_meta": { "description": "The number of spaces which have solution set to observability." diff --git a/x-pack/test/spaces_api_integration/common/suites/create.ts b/x-pack/test/spaces_api_integration/common/suites/create.ts index c7aab659ce960f..fc2bd1b841ccc5 100644 --- a/x-pack/test/spaces_api_integration/common/suites/create.ts +++ b/x-pack/test/spaces_api_integration/common/suites/create.ts @@ -71,7 +71,7 @@ export function createTestSuiteFactory(esArchiver: any, supertest: SuperTest Date: Tue, 18 Jun 2024 11:35:32 +0200 Subject: [PATCH 016/123] config-schema: implements `intersection` (#186269) ## Summary Fix https://github.com/elastic/kibana/issues/185018 Add a new `schema.intersection` (alias `schema.allOf` for consistency with `schema.oneOf`) API to `@kbn/config-schema`, allowing to create object schema based on the intersection of other object schemas. ```ts const mySchema = schema.intersection([ schema.object({ someKey: schema.string(), }), schema.object({ anotherKey: schema.string(), }) ]); ``` --- packages/kbn-config-schema/README.md | 25 +++ packages/kbn-config-schema/index.ts | 163 ++++++++++++++++++ packages/kbn-config-schema/src/types/index.ts | 10 +- .../src/types/intersection_type.test.ts | 67 +++++++ .../src/types/intersection_type.ts | 31 ++++ .../src/types/object_type.ts | 9 + packages/kbn-config-schema/src/types/type.ts | 6 +- 7 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 packages/kbn-config-schema/src/types/intersection_type.test.ts create mode 100644 packages/kbn-config-schema/src/types/intersection_type.ts diff --git a/packages/kbn-config-schema/README.md b/packages/kbn-config-schema/README.md index 5916f49ef28362..45e46c078baee1 100644 --- a/packages/kbn-config-schema/README.md +++ b/packages/kbn-config-schema/README.md @@ -21,6 +21,7 @@ Kibana configuration entries providing developers with a fully typed model of th - [`schema.object()`](#schemaobject) - [`schema.recordOf()`](#schemarecordof) - [`schema.mapOf()`](#schemamapof) + - [`schema.allOf` / `schema.intersection`](#schemaintersection--schemaallof) - [Advanced types](#advanced-types) - [`schema.oneOf()`](#schemaoneof) - [`schema.any()`](#schemaany) @@ -295,6 +296,30 @@ __Notes:__ * You can use a union of literal types as a record's key schema to restrict record to a specific set of keys, e.g. `schema.oneOf([schema.literal('isEnabled'), schema.literal('name')])`. * `schema.mapOf()` also supports a json string as input if it can be safely parsed using `JSON.parse` and if the resulting value is a plain object. +#### `schema.intersection()` / `schema.allOf()` + +Creates an `object` schema being the intersection of the provided `object` schemas. +Note that schema construction will throw an error if some of the intersection schema share the same key(s). + +See the documentation for [schema.object](#schemaobject). + +__Options:__ +* `defaultValue: TObject | Reference | (() => TObject)` - defines a default value, see [Default values](#default-values) section for more details. +* `validate: (value: TObject) => string | void` - defines a custom validator function, see [Custom validation](#custom-validation) section for more details. +* `unknowns: 'allow' | 'ignore' | 'forbid'` - indicates whether unknown object properties should be allowed, ignored, or forbidden. It's `forbid` by default. + +__Usage:__ +```typescript +const mySchema = schema.intersection([ + schema.object({ + someKey: schema.string(), + }), + schema.object({ + anotherKey: schema.string(), + }) +]); +``` + ### Advanced types #### `schema.oneOf()` diff --git a/packages/kbn-config-schema/index.ts b/packages/kbn-config-schema/index.ts index c6ef8c2ce99dc5..8195631606381b 100644 --- a/packages/kbn-config-schema/index.ts +++ b/packages/kbn-config-schema/index.ts @@ -23,6 +23,8 @@ import { ConditionalTypeValue, DurationOptions, DurationType, + IntersectionType, + IntersectionTypeOptions, IpOptions, IpType, LiteralType, @@ -34,6 +36,7 @@ import { NumberType, ObjectType, ObjectTypeOptions, + ObjectResultType, Props, NullableProps, RecordOfOptions, @@ -199,6 +202,164 @@ function oneOf>>( return new UnionType(types, options); } +function allOf< + A extends Props, + B extends Props, + C extends Props, + D extends Props, + E extends Props, + F extends Props, + G extends Props, + H extends Props, + I extends Props, + J extends Props, + K extends Props +>( + types: [ + ObjectType, + ObjectType
, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType + ], + options?: UnionTypeOptions +): Type>; +function allOf< + A extends Props, + B extends Props, + C extends Props, + D extends Props, + E extends Props, + F extends Props, + G extends Props, + H extends Props, + I extends Props, + J extends Props +>( + types: [ + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType + ], + options?: UnionTypeOptions +): Type>; +function allOf< + A extends Props, + B extends Props, + C extends Props, + D extends Props, + E extends Props, + F extends Props, + G extends Props, + H extends Props, + I extends Props +>( + types: [ + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType + ], + options?: UnionTypeOptions +): Type>; +function allOf< + A extends Props, + B extends Props, + C extends Props, + D extends Props, + E extends Props, + F extends Props, + G extends Props, + H extends Props +>( + types: [ + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType + ], + options?: UnionTypeOptions +): Type>; +function allOf< + A extends Props, + B extends Props, + C extends Props, + D extends Props, + E extends Props, + F extends Props, + G extends Props +>( + types: [ + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType, + ObjectType + ], + options?: UnionTypeOptions +): Type>; +function allOf< + A extends Props, + B extends Props, + C extends Props, + D extends Props, + E extends Props, + F extends Props +>( + types: [ObjectType, ObjectType, ObjectType, ObjectType, ObjectType, ObjectType], + options?: UnionTypeOptions +): Type>; +function allOf( + types: [ObjectType, ObjectType, ObjectType, ObjectType, ObjectType], + options?: UnionTypeOptions +): Type>; +function allOf( + types: [ObjectType, ObjectType, ObjectType, ObjectType], + options?: UnionTypeOptions +): Type>; +function allOf( + types: [ObjectType, ObjectType, ObjectType], + options?: UnionTypeOptions +): Type>; +function allOf( + types: [ObjectType, ObjectType], + options?: UnionTypeOptions +): Type>; +function allOf( + types: [ObjectType], + options?: UnionTypeOptions +): Type>; +function allOf>>( + types: RTS, + options?: IntersectionTypeOptions +): Type { + return new IntersectionType(types, options); +} + function contextRef(key: string): ContextReference { return new ContextReference(key); } @@ -225,6 +386,7 @@ function lazy(id: string) { } export const schema = { + allOf, any, arrayOf, boolean, @@ -233,6 +395,7 @@ export const schema = { conditional, contextRef, duration, + intersection: allOf, ip, lazy, literal, diff --git a/packages/kbn-config-schema/src/types/index.ts b/packages/kbn-config-schema/src/types/index.ts index 78eab0957557de..4c92bb6d078dcc 100644 --- a/packages/kbn-config-schema/src/types/index.ts +++ b/packages/kbn-config-schema/src/types/index.ts @@ -20,13 +20,21 @@ export type { ConditionalTypeValue } from './conditional_type'; export { ConditionalType } from './conditional_type'; export type { DurationOptions } from './duration_type'; export { DurationType } from './duration_type'; +export type { IntersectionTypeOptions } from './intersection_type'; +export { IntersectionType } from './intersection_type'; export { LiteralType } from './literal_type'; export { MaybeType } from './maybe_type'; export type { MapOfOptions } from './map_type'; export { MapOfType } from './map_type'; export type { NumberOptions } from './number_type'; export { NumberType } from './number_type'; -export type { ObjectTypeOptions, Props, NullableProps, TypeOf } from './object_type'; +export type { + ObjectTypeOptions, + Props, + NullableProps, + TypeOf, + ObjectResultType, +} from './object_type'; export { ObjectType } from './object_type'; export type { RecordOfOptions } from './record_type'; export { RecordOfType } from './record_type'; diff --git a/packages/kbn-config-schema/src/types/intersection_type.test.ts b/packages/kbn-config-schema/src/types/intersection_type.test.ts new file mode 100644 index 00000000000000..cf1262da0550b1 --- /dev/null +++ b/packages/kbn-config-schema/src/types/intersection_type.test.ts @@ -0,0 +1,67 @@ +/* + * 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 { schema, TypeOf } from '../..'; + +describe('schema.allOf', () => { + it('validates all parts of the intersection', () => { + const type = schema.allOf([ + schema.object({ foo: schema.string() }), + schema.object({ bar: schema.string() }), + ]); + + expect(type.validate({ foo: 'hello', bar: 'dolly' })).toEqual({ foo: 'hello', bar: 'dolly' }); + }); + + it('throw error when one part of the intersection is not matched with the correct error message', () => { + const type = schema.allOf([ + schema.object({ foo: schema.string() }), + schema.object({ bar: schema.string() }), + ]); + + expect(() => type.validate({ foo: 'something' })).toThrowErrorMatchingInlineSnapshot( + `"[bar]: expected value of type [string] but got [undefined]"` + ); + }); + + it('supports default value', () => { + const type = schema.allOf([ + schema.object({ foo: schema.string() }), + schema.object({ bar: schema.string({ defaultValue: 'default' }) }), + ]); + + expect(type.validate({ foo: 'hello' })).toEqual({ foo: 'hello', bar: 'default' }); + }); + + it('throw error if multiple schemas define the same key', () => { + expect(() => + schema.allOf([ + schema.object({ foo: schema.string() }), + schema.object({ foo: schema.literal('bar') }), + ]) + ).toThrowErrorMatchingInlineSnapshot(`"Duplicate key found in intersection: 'foo'"`); + }); + + it('has the right type inference', () => { + const resultingSchema = schema.object({ + foo: schema.string(), + bar: schema.string(), + }); + type ResultingType = TypeOf; + + const type = schema.allOf([ + schema.object({ foo: schema.string() }), + schema.object({ bar: schema.string() }), + ]); + + // asserting the type is the expected one + const output: ResultingType = type.validate({ foo: 'hello', bar: 'dolly' }); + // required to make TS happy + expect(output).toEqual({ foo: 'hello', bar: 'dolly' }); + }); +}); diff --git a/packages/kbn-config-schema/src/types/intersection_type.ts b/packages/kbn-config-schema/src/types/intersection_type.ts new file mode 100644 index 00000000000000..766a0786103fc3 --- /dev/null +++ b/packages/kbn-config-schema/src/types/intersection_type.ts @@ -0,0 +1,31 @@ +/* + * 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 { ObjectType, Props, ObjectTypeOptions } from './object_type'; + +export type IntersectionTypeOptions = ObjectTypeOptions; + +export class IntersectionType< + RTS extends Array>, + T extends Props +> extends ObjectType { + constructor(types: RTS, options?: IntersectionTypeOptions) { + const props = types.reduce((mergedProps, type) => { + Object.entries(type.getPropSchemas() as Record).forEach(([key, value]) => { + if (mergedProps[key] !== undefined) { + throw new Error(`Duplicate key found in intersection: '${key}'`); + } + mergedProps[key as keyof T] = value; + }); + + return mergedProps; + }, {} as T); + + super(props, options); + } +} diff --git a/packages/kbn-config-schema/src/types/object_type.ts b/packages/kbn-config-schema/src/types/object_type.ts index d5193b5e0fc38c..423d6030b30b0f 100644 --- a/packages/kbn-config-schema/src/types/object_type.ts +++ b/packages/kbn-config-schema/src/types/object_type.ts @@ -223,6 +223,15 @@ export class ObjectType

extends Type> } } + /** + * Return the schema for this object's underlying properties + * + * @internal should only be used internal for type reflection + */ + public getPropSchemas(): P { + return this.props; + } + validateKey(key: string, value: any) { if (!this.propSchemas[key]) { throw new Error(`${key} is not a valid part of this schema`); diff --git a/packages/kbn-config-schema/src/types/type.ts b/packages/kbn-config-schema/src/types/type.ts index 652eae077d5aff..3b8808dba61af0 100644 --- a/packages/kbn-config-schema/src/types/type.ts +++ b/packages/kbn-config-schema/src/types/type.ts @@ -125,7 +125,11 @@ export abstract class Type { return this; } - public validate(value: any, context: Record = {}, namespace?: string): V { + /** + * Validates the provided value against this schema. + * If valid, the resulting output will be returned, otherwise an exception will be thrown. + */ + public validate(value: unknown, context: Record = {}, namespace?: string): V { const { value: validatedValue, error } = this.internalSchema.validate(value, { context, presence: 'required', From cf67fede6e0ac1b45210bd5300f8c099a855ea6f Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Tue, 18 Jun 2024 11:42:45 +0200 Subject: [PATCH 017/123] [Defend Workflows] Skip Cypress tests on MKI executions (#186120) ## Summary The `x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/scan.cy.ts` test is failing on MKI environments (the periodic pipeline). This is because the test in order to work need to have a feature flag enabled. FF are not currently supported on MKI environments, that is why in this PR we are skipping it from MKI environments by adding `@skipInServerlessMKI` label to it. Co-authored-by: Ash <1849116+ashokaditya@users.noreply.github.com> --- .../cypress/e2e/response_actions/response_console/scan.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/scan.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/scan.cy.ts index f05e0581332cf9..59c6916f23fff4 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/scan.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/scan.cy.ts @@ -33,7 +33,7 @@ describe( ], }, }, - tags: ['@ess', '@serverless'], + tags: ['@ess', '@serverless', '@skipInServerlessMKI'], }, () => { beforeEach(() => { From 3a2e1621f423613b62eb299d7c21fa61d6138bed Mon Sep 17 00:00:00 2001 From: Antonio Date: Tue, 18 Jun 2024 11:45:41 +0200 Subject: [PATCH 018/123] [ResponseOps][Connectors] SSL for Cases Webhook (#185925) Fixes #180255 ## Summary Adds API support and UI for CA and client-side SSL certificate authentication to the Cases webhook connector. aux This PR is to merge a feature branch into `main`. This feature branch is composed of the following PRs: - https://github.com/elastic/kibana/pull/183711 - https://github.com/elastic/kibana/pull/183919 - https://github.com/elastic/kibana/pull/184313 ### How to test @cnasikas kindly provided a node server that can be setup locally to test the certificates against. Ping me offline and i will send you the rar. You will need to configure a connector of type `Cases Webhook connector`. #### Configuring `Authentication`: The project folder has two sets of keys, one for Alice and one for Bob. The Alice keys should work and the Bob keys are expected to be unauthorized. - For `CRT and KEY File` use: - `alice_cert.pem` and `alice_key.pem` respectively (or `bob_*`) - For `PFX File` use: - `alice.p12` or `bob.p12`. - Toggle `Add certificate authority`. - Select `Verification mode` to be `none`. #### Configuring `Create case`: Only the URL is relevant. It should be `https://localhost:9999/authenticate`. Everything else can have whatever values you want. ### Release Notes The Cases webhook connector now supports SSL certificate authentication. --- .../connector_types.test.ts.snap | 288 ++++++- .../common/{webhook => auth}/constants.ts | 8 +- .../webhook => common/auth}/mocks.ts | 0 .../stack_connectors/common/auth/schema.ts | 61 ++ .../stack_connectors/common/auth/types.ts | 20 + .../common/auth/utils.test.ts | 209 +++++ .../stack_connectors/common/auth/utils.ts | 101 +++ .../public/common/auth/auth_config.test.tsx | 483 +++++++++++ .../public/common/auth/auth_config.tsx | 292 +++++++ .../common/auth/basic_auth_fields.test.tsx | 112 +++ .../public/common/auth/basic_auth_fields.tsx | 60 ++ .../common/auth/ssl_cert_fields.test.tsx | 223 +++++ .../public/common/auth/ssl_cert_fields.tsx | 138 +++ .../public/common/auth/translations.ts | 159 ++++ .../cases_webhook/steps/auth.tsx | 175 +--- .../cases_webhook/translations.ts | 78 -- .../cases_webhook/webhook_connectors.test.tsx | 459 +++++----- .../public/connector_types/lib/test_utils.tsx | 15 + .../connector_types/webhook/translations.ts | 159 ---- .../webhook/webhook_connectors.test.tsx | 24 +- .../webhook/webhook_connectors.tsx | 407 +-------- .../connector_types/cases_webhook/index.ts | 8 +- .../connector_types/cases_webhook/schema.ts | 43 +- .../cases_webhook/service.test.ts | 788 ++++++++++++++++-- .../connector_types/cases_webhook/service.ts | 52 +- .../cases_webhook/translations.ts | 9 +- .../connector_types/cases_webhook/types.ts | 23 - .../cases_webhook/validators.ts | 31 +- .../server/connector_types/index.ts | 2 +- .../server/connector_types/lib/nullable.ts | 14 - .../connector_types/webhook/index.test.ts | 30 +- .../server/connector_types/webhook/index.ts | 132 +-- .../server/connector_types/webhook/schema.ts | 32 + .../server/connector_types/webhook/types.ts | 34 + .../plugins/stack_connectors/server/index.ts | 2 +- .../translations/translations/fr-FR.json | 37 - .../translations/translations/ja-JP.json | 37 - .../translations/translations/zh-CN.json | 37 - .../actions/connector_types/cases_webhook.ts | 2 +- .../perform_bulk_action.ts | 4 +- 40 files changed, 3324 insertions(+), 1464 deletions(-) rename x-pack/plugins/stack_connectors/common/{webhook => auth}/constants.ts (79%) rename x-pack/plugins/stack_connectors/{server/connector_types/webhook => common/auth}/mocks.ts (100%) create mode 100644 x-pack/plugins/stack_connectors/common/auth/schema.ts create mode 100644 x-pack/plugins/stack_connectors/common/auth/types.ts create mode 100644 x-pack/plugins/stack_connectors/common/auth/utils.test.ts create mode 100644 x-pack/plugins/stack_connectors/common/auth/utils.ts create mode 100644 x-pack/plugins/stack_connectors/public/common/auth/auth_config.test.tsx create mode 100644 x-pack/plugins/stack_connectors/public/common/auth/auth_config.tsx create mode 100644 x-pack/plugins/stack_connectors/public/common/auth/basic_auth_fields.test.tsx create mode 100644 x-pack/plugins/stack_connectors/public/common/auth/basic_auth_fields.tsx create mode 100644 x-pack/plugins/stack_connectors/public/common/auth/ssl_cert_fields.test.tsx create mode 100644 x-pack/plugins/stack_connectors/public/common/auth/ssl_cert_fields.tsx create mode 100644 x-pack/plugins/stack_connectors/public/common/auth/translations.ts delete mode 100644 x-pack/plugins/stack_connectors/server/connector_types/lib/nullable.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/webhook/schema.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/webhook/types.ts diff --git a/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap b/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap index 84f1c1966747b7..c9c525272a3914 100644 --- a/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap +++ b/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap @@ -1139,6 +1139,117 @@ Object { "presence": "optional", }, "keys": Object { + "authType": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "matches": Array [ + Object { + "schema": Object { + "allow": Array [ + "webhook-authentication-basic", + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + Object { + "schema": Object { + "allow": Array [ + "webhook-authentication-ssl", + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + Object { + "schema": Object { + "allow": Array [ + null, + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "alternatives", + }, + "ca": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + "certType": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "matches": Array [ + Object { + "schema": Object { + "allow": Array [ + "ssl-crt-key", + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + Object { + "schema": Object { + "allow": Array [ + "ssl-pfx", + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "alternatives", + }, "createCommentJson": Object { "flags": Object { "default": null, @@ -1399,7 +1510,7 @@ Object { }, "headers": Object { "flags": Object { - "default": [Function], + "default": null, "error": [Function], "presence": "optional", }, @@ -1541,6 +1652,57 @@ Object { ], "type": "string", }, + "verificationMode": Object { + "flags": Object { + "default": [Function], + "error": [Function], + "presence": "optional", + }, + "matches": Array [ + Object { + "schema": Object { + "allow": Array [ + "none", + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + Object { + "schema": Object { + "allow": Array [ + "certificate", + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + Object { + "schema": Object { + "allow": Array [ + "full", + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + ], + "metas": Array [ + Object { + "x-oas-optional": true, + }, + ], + "type": "alternatives", + }, "viewIncidentUrl": Object { "flags": Object { "error": [Function], @@ -1575,6 +1737,82 @@ Object { "presence": "optional", }, "keys": Object { + "crt": Object { + "flags": Object { + "default": null, + "error": [Function], + "presence": "optional", + }, + "matches": Array [ + Object { + "schema": Object { + "flags": Object { + "error": [Function], + }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + }, + Object { + "schema": Object { + "allow": Array [ + null, + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + ], + "type": "alternatives", + }, + "key": Object { + "flags": Object { + "default": null, + "error": [Function], + "presence": "optional", + }, + "matches": Array [ + Object { + "schema": Object { + "flags": Object { + "error": [Function], + }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + }, + Object { + "schema": Object { + "allow": Array [ + null, + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + ], + "type": "alternatives", + }, "password": Object { "flags": Object { "default": null, @@ -1613,6 +1851,44 @@ Object { ], "type": "alternatives", }, + "pfx": Object { + "flags": Object { + "default": null, + "error": [Function], + "presence": "optional", + }, + "matches": Array [ + Object { + "schema": Object { + "flags": Object { + "error": [Function], + }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + }, + Object { + "schema": Object { + "allow": Array [ + null, + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + ], + "type": "alternatives", + }, "user": Object { "flags": Object { "default": null, @@ -1657,6 +1933,14 @@ Object { "objects": false, }, }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], "type": "object", } `; @@ -32515,7 +32799,7 @@ Object { }, "headers": Object { "flags": Object { - "default": [Function], + "default": null, "error": [Function], "presence": "optional", }, diff --git a/x-pack/plugins/stack_connectors/common/webhook/constants.ts b/x-pack/plugins/stack_connectors/common/auth/constants.ts similarity index 79% rename from x-pack/plugins/stack_connectors/common/webhook/constants.ts rename to x-pack/plugins/stack_connectors/common/auth/constants.ts index 48134762b34db0..bdd5b7352f9217 100644 --- a/x-pack/plugins/stack_connectors/common/webhook/constants.ts +++ b/x-pack/plugins/stack_connectors/common/auth/constants.ts @@ -5,7 +5,7 @@ * 2.0. */ -export enum WebhookAuthType { +export enum AuthType { Basic = 'webhook-authentication-basic', SSL = 'webhook-authentication-ssl', } @@ -14,3 +14,9 @@ export enum SSLCertType { CRT = 'ssl-crt-key', PFX = 'ssl-pfx', } + +export enum WebhookMethods { + PATCH = 'patch', + POST = 'post', + PUT = 'put', +} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/mocks.ts b/x-pack/plugins/stack_connectors/common/auth/mocks.ts similarity index 100% rename from x-pack/plugins/stack_connectors/server/connector_types/webhook/mocks.ts rename to x-pack/plugins/stack_connectors/common/auth/mocks.ts diff --git a/x-pack/plugins/stack_connectors/common/auth/schema.ts b/x-pack/plugins/stack_connectors/common/auth/schema.ts new file mode 100644 index 00000000000000..91754b38f84dbe --- /dev/null +++ b/x-pack/plugins/stack_connectors/common/auth/schema.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +import { schema } from '@kbn/config-schema'; +import { AuthType, SSLCertType } from './constants'; + +export const authTypeSchema = schema.maybe( + schema.oneOf( + [schema.literal(AuthType.Basic), schema.literal(AuthType.SSL), schema.literal(null)], + { + defaultValue: AuthType.Basic, + } + ) +); + +export const hasAuthSchema = schema.boolean({ defaultValue: true }); + +export const AuthConfiguration = { + hasAuth: hasAuthSchema, + authType: authTypeSchema, + certType: schema.maybe( + schema.oneOf([schema.literal(SSLCertType.CRT), schema.literal(SSLCertType.PFX)]) + ), + ca: schema.maybe(schema.string()), + verificationMode: schema.maybe( + schema.oneOf([schema.literal('none'), schema.literal('certificate'), schema.literal('full')]) + ), +}; + +export const SecretConfiguration = { + user: schema.nullable(schema.string()), + password: schema.nullable(schema.string()), + crt: schema.nullable(schema.string()), + key: schema.nullable(schema.string()), + pfx: schema.nullable(schema.string()), +}; + +export const SecretConfigurationSchemaValidation = { + validate: (secrets: any) => { + // user and password must be set together (or not at all) + if (!secrets.password && !secrets.user && !secrets.crt && !secrets.key && !secrets.pfx) return; + if (secrets.password && secrets.user && !secrets.crt && !secrets.key && !secrets.pfx) return; + if (secrets.crt && secrets.key && !secrets.user && !secrets.pfx) return; + if (!secrets.crt && !secrets.key && !secrets.user && secrets.pfx) return; + return i18n.translate('xpack.stackConnectors.webhook.invalidSecrets', { + defaultMessage: + 'must specify one of the following schemas: user and password; crt and key (with optional password); or pfx (with optional password)', + }); + }, +}; + +export const SecretConfigurationSchema = schema.object( + SecretConfiguration, + SecretConfigurationSchemaValidation +); diff --git a/x-pack/plugins/stack_connectors/common/auth/types.ts b/x-pack/plugins/stack_connectors/common/auth/types.ts new file mode 100644 index 00000000000000..ba09bc1a23d68a --- /dev/null +++ b/x-pack/plugins/stack_connectors/common/auth/types.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 { TypeOf } from '@kbn/config-schema'; +import { + AuthConfiguration, + authTypeSchema, + hasAuthSchema, + SecretConfigurationSchema, +} from './schema'; + +export type HasAuth = TypeOf; +export type AuthTypeName = TypeOf; +export type SecretsConfigurationType = TypeOf; +export type CAType = TypeOf; +export type VerificationModeType = TypeOf; diff --git a/x-pack/plugins/stack_connectors/common/auth/utils.test.ts b/x-pack/plugins/stack_connectors/common/auth/utils.test.ts new file mode 100644 index 00000000000000..78209d0d1db7bb --- /dev/null +++ b/x-pack/plugins/stack_connectors/common/auth/utils.test.ts @@ -0,0 +1,209 @@ +/* + * 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 { AuthType } from './constants'; +import { buildConnectorAuth, isBasicAuth, validateConnectorAuthConfiguration } from './utils'; + +describe('utils', () => { + describe('isBasicAuth', () => { + it('returns false when hasAuth is false and authType is undefined', () => { + expect( + isBasicAuth({ + hasAuth: false, + authType: undefined, + }) + ).toBe(false); + }); + + it('returns false when hasAuth is false and authType is basic', () => { + expect( + isBasicAuth({ + hasAuth: false, + authType: AuthType.Basic, + }) + ).toBe(false); + }); + + it('returns false when hasAuth is true and authType is ssl', () => { + expect( + isBasicAuth({ + hasAuth: true, + authType: AuthType.SSL, + }) + ).toBe(false); + }); + + it('returns true when hasAuth is true and authType is undefined', () => { + expect( + isBasicAuth({ + hasAuth: true, + authType: undefined, + }) + ).toBe(true); + }); + + it('returns true when hasAuth is true and authType is basic', () => { + expect( + isBasicAuth({ + hasAuth: true, + authType: AuthType.Basic, + }) + ).toBe(true); + }); + }); + + describe('validateConnectorAuthConfiguration', () => { + it('does not throw with correct authType=basic params', () => { + expect(() => + validateConnectorAuthConfiguration({ + hasAuth: true, + authType: AuthType.Basic, + basicAuth: { auth: { username: 'foo', password: 'bar' } }, + sslOverrides: {}, + connectorName: 'foobar', + }) + ).not.toThrow(); + }); + + it('does not throw with correct authType=undefined params', () => { + expect(() => + validateConnectorAuthConfiguration({ + hasAuth: true, + authType: undefined, + basicAuth: { auth: { username: 'foo', password: 'bar' } }, + sslOverrides: {}, + connectorName: 'foobar', + }) + ).not.toThrow(); + }); + + it('throws when type is basic and the username is missing', () => { + expect(() => + validateConnectorAuthConfiguration({ + hasAuth: true, + authType: undefined, + // @ts-ignore: that's what we are testing + basicAuth: { auth: { password: 'bar' } }, + sslOverrides: {}, + connectorName: 'Foobar', + }) + ).toThrow('[Action]Foobar: Wrong configuration.'); + }); + + it('throws when type is basic and the password is missing', () => { + expect(() => + validateConnectorAuthConfiguration({ + hasAuth: true, + authType: undefined, + // @ts-ignore: that's what we are testing + basicAuth: { auth: { username: 'foo' } }, + sslOverrides: {}, + connectorName: 'Foobar', + }) + ).toThrow('[Action]Foobar: Wrong configuration.'); + }); + + it('does not throw with correct authType=ssl params', () => { + expect(() => + validateConnectorAuthConfiguration({ + hasAuth: true, + authType: AuthType.SSL, + basicAuth: {}, + sslOverrides: { verificationMode: 'none', passphrase: 'passphrase' }, + connectorName: 'foobar', + }) + ).not.toThrow(); + }); + + it('throws when type is SSL and the sslOverrides are missing', () => { + expect(() => + validateConnectorAuthConfiguration({ + hasAuth: true, + authType: AuthType.SSL, + basicAuth: {}, + sslOverrides: {}, + connectorName: 'Foobar', + }) + ).toThrow('[Action]Foobar: Wrong configuration.'); + }); + }); + + describe('buildConnectorAuth', () => { + it('returns empty objects when hasAuth=false', () => { + expect( + buildConnectorAuth({ + hasAuth: false, + authType: AuthType.SSL, + secrets: { user: 'foo', password: 'bar', crt: null, key: null, pfx: null }, + verificationMode: undefined, + ca: undefined, + }) + ).toEqual({ basicAuth: {}, sslOverrides: {} }); + }); + + it('builds basicAuth correctly with authType=basic', () => { + expect( + buildConnectorAuth({ + hasAuth: true, + authType: AuthType.Basic, + secrets: { user: 'foo', password: 'bar', crt: null, key: null, pfx: null }, + verificationMode: undefined, + ca: undefined, + }) + ).toEqual({ basicAuth: { auth: { username: 'foo', password: 'bar' } }, sslOverrides: {} }); + }); + + it('builds basicAuth correctly with hasAuth=true and authType=undefined', () => { + expect( + buildConnectorAuth({ + hasAuth: true, + authType: undefined, + secrets: { user: 'foo', password: 'bar', crt: null, key: null, pfx: null }, + verificationMode: undefined, + ca: undefined, + }) + ).toEqual({ basicAuth: { auth: { username: 'foo', password: 'bar' } }, sslOverrides: {} }); + }); + + it('builds sslOverrides correctly with authType=ssl', () => { + expect( + buildConnectorAuth({ + hasAuth: true, + authType: AuthType.SSL, + secrets: { user: 'foo', password: 'bar', crt: 'null', key: 'null', pfx: 'null' }, + verificationMode: 'certificate', + ca: 'foobar?', + }) + ).toMatchInlineSnapshot(` + Object { + "basicAuth": Object {}, + "sslOverrides": Object { + "ca": Object { + "data": Array [ + 126, + 138, + 27, + 106, + ], + "type": "Buffer", + }, + "passphrase": "bar", + "pfx": Object { + "data": Array [ + 158, + 233, + 101, + ], + "type": "Buffer", + }, + "verificationMode": "certificate", + }, + } + `); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/common/auth/utils.ts b/x-pack/plugins/stack_connectors/common/auth/utils.ts new file mode 100644 index 00000000000000..8c16ee3316274e --- /dev/null +++ b/x-pack/plugins/stack_connectors/common/auth/utils.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { isString, isEmpty } from 'lodash'; + +import type { SSLSettings } from '@kbn/actions-plugin/server/types'; +import type { + AuthTypeName, + CAType, + HasAuth, + SecretsConfigurationType, + VerificationModeType, +} from './types'; + +import { AuthType } from './constants'; + +// For backwards compatibility with connectors created before authType was added, interpret a +// hasAuth: true and undefined authType as basic auth +export const isBasicAuth = ({ + hasAuth, + authType, +}: { + hasAuth: HasAuth; + authType: AuthTypeName; +}): boolean => hasAuth && (authType === AuthType.Basic || !authType); + +interface BasicAuthResponse { + auth?: { username: string; password: string }; +} + +export const buildConnectorAuth = ({ + hasAuth, + authType, + secrets, + verificationMode, + ca, +}: { + hasAuth: HasAuth; + authType: AuthTypeName; + secrets: SecretsConfigurationType; + verificationMode: VerificationModeType; + ca: CAType; +}): { basicAuth: BasicAuthResponse; sslOverrides: SSLSettings } => { + let basicAuth: BasicAuthResponse = {}; + let sslOverrides: SSLSettings = {}; + let sslCertificate = {}; + + if (isBasicAuth({ hasAuth, authType })) { + basicAuth = + isString(secrets.user) && isString(secrets.password) + ? { auth: { username: secrets.user, password: secrets.password } } + : {}; + } else if (hasAuth && authType === AuthType.SSL) { + sslCertificate = + (isString(secrets.crt) && isString(secrets.key)) || isString(secrets.pfx) + ? isString(secrets.pfx) + ? { + pfx: Buffer.from(secrets.pfx, 'base64'), + ...(isString(secrets.password) ? { passphrase: secrets.password } : {}), + } + : { + cert: Buffer.from(secrets.crt!, 'base64'), + key: Buffer.from(secrets.key!, 'base64'), + ...(isString(secrets.password) ? { passphrase: secrets.password } : {}), + } + : {}; + } + + sslOverrides = { + ...sslCertificate, + ...(verificationMode ? { verificationMode } : {}), + ...(ca ? { ca: Buffer.from(ca, 'base64') } : {}), + }; + + return { basicAuth, sslOverrides }; +}; + +export const validateConnectorAuthConfiguration = ({ + hasAuth, + authType, + basicAuth, + sslOverrides, + connectorName, +}: { + hasAuth: HasAuth; + authType: AuthTypeName; + basicAuth: BasicAuthResponse; + sslOverrides: SSLSettings; + connectorName: string; +}) => { + if ( + (isBasicAuth({ hasAuth, authType }) && + (!basicAuth.auth?.password || !basicAuth.auth?.username)) || + (authType === AuthType.SSL && isEmpty(sslOverrides)) + ) { + throw Error(`[Action]${connectorName}: Wrong configuration.`); + } +}; diff --git a/x-pack/plugins/stack_connectors/public/common/auth/auth_config.test.tsx b/x-pack/plugins/stack_connectors/public/common/auth/auth_config.test.tsx new file mode 100644 index 00000000000000..6a6e15ac378dec --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/common/auth/auth_config.test.tsx @@ -0,0 +1,483 @@ +/* + * 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 { AuthConfig } from './auth_config'; +import { render, screen, waitFor, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { AuthType, SSLCertType } from '../../../common/auth/constants'; +import { AuthFormTestProvider } from '../../connector_types/lib/test_utils'; + +describe('AuthConfig renders', () => { + const onSubmit = jest.fn(); + + it('renders all fields for authType=None', async () => { + const testFormData = { + config: { + hasAuth: false, + }, + __internal__: { + hasCA: true, + hasHeaders: true, + }, + }; + render( + + + + ); + + expect(await screen.findByTestId('webhookViewHeadersSwitch')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookHeaderText')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookHeadersKeyInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookHeadersValueInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookAddHeaderButton')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookViewCASwitch')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCAInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookVerificationModeSelect')).toBeInTheDocument(); + expect(await screen.findByTestId('authNone')).toBeInTheDocument(); + expect(await screen.findByTestId('authBasic')).toBeInTheDocument(); + expect(screen.queryByTestId('basicAuthFields')).not.toBeInTheDocument(); + expect(await screen.findByTestId('authSSL')).toBeInTheDocument(); + expect(screen.queryByTestId('sslCertFields')).not.toBeInTheDocument(); + }); + + it('toggles headers as expected', async () => { + const testFormData = { + config: { + hasAuth: false, + }, + __internal__: { + hasCA: false, + hasHeaders: false, + }, + }; + render( + + + + ); + + const headersToggle = await screen.findByTestId('webhookViewHeadersSwitch'); + + expect(headersToggle).toBeInTheDocument(); + + userEvent.click(headersToggle); + + expect(await screen.findByTestId('webhookHeaderText')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookHeadersKeyInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookHeadersValueInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookAddHeaderButton')).toBeInTheDocument(); + }); + + it('toggles CA as expected', async () => { + const testFormData = { + config: { + hasAuth: false, + }, + __internal__: { + hasCA: false, + hasHeaders: false, + }, + }; + + render( + + + + ); + + const caToggle = await screen.findByTestId('webhookViewCASwitch'); + + expect(caToggle).toBeInTheDocument(); + + userEvent.click(caToggle); + + expect(await screen.findByTestId('webhookViewCASwitch')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCAInput')).toBeInTheDocument(); + + const verificationModeSelect = await screen.findByTestId('webhookVerificationModeSelect'); + + expect(verificationModeSelect).toBeInTheDocument(); + + ['None', 'Certificate', 'Full'].forEach((optionName) => { + const select = within(verificationModeSelect); + + expect(select.getByRole('option', { name: optionName })); + }); + }); + + it('renders all fields for authType=Basic', async () => { + const testFormData = { + config: { + hasAuth: true, + authType: AuthType.Basic, + }, + secrets: { + user: 'user', + password: 'pass', + }, + }; + + render( + + + + ); + + expect(await screen.findByTestId('webhookViewHeadersSwitch')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookViewCASwitch')).toBeInTheDocument(); + expect(await screen.findByTestId('authNone')).toBeInTheDocument(); + expect(await screen.findByTestId('authBasic')).toBeInTheDocument(); + expect(await screen.findByTestId('basicAuthFields')).toBeInTheDocument(); + expect(await screen.findByTestId('authSSL')).toBeInTheDocument(); + expect(screen.queryByTestId('sslCertFields')).not.toBeInTheDocument(); + }); + + it('renders all fields for authType=SSL', async () => { + const testFormData = { + config: { + hasAuth: true, + authType: AuthType.SSL, + certType: SSLCertType.CRT, + }, + secrets: { + crt: Buffer.from('some binary string').toString('base64'), + key: Buffer.from('some binary string').toString('base64'), + }, + }; + render( + + + + ); + + expect(await screen.findByTestId('webhookViewHeadersSwitch')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookViewCASwitch')).toBeInTheDocument(); + expect(await screen.findByTestId('authNone')).toBeInTheDocument(); + expect(await screen.findByTestId('authBasic')).toBeInTheDocument(); + expect(screen.queryByTestId('basicAuthFields')).not.toBeInTheDocument(); + expect(await screen.findByTestId('authSSL')).toBeInTheDocument(); + expect(await screen.findByTestId('sslCertFields')).toBeInTheDocument(); + }); + + it('renders all fields for authType=SSL and certType=PFX', async () => { + const testFormData = { + config: { + hasAuth: true, + authType: AuthType.SSL, + certType: SSLCertType.PFX, + }, + secrets: { + crt: Buffer.from('some binary string').toString('base64'), + key: Buffer.from('some binary string').toString('base64'), + }, + }; + render( + + + + ); + + expect(await screen.findByTestId('webhookViewHeadersSwitch')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookViewCASwitch')).toBeInTheDocument(); + expect(await screen.findByTestId('authNone')).toBeInTheDocument(); + expect(await screen.findByTestId('authBasic')).toBeInTheDocument(); + expect(screen.queryByTestId('basicAuthFields')).not.toBeInTheDocument(); + expect(await screen.findByTestId('authSSL')).toBeInTheDocument(); + expect(await screen.findByTestId('sslCertFields')).toBeInTheDocument(); + }); + + describe('Validation', () => { + const defaultTestFormData = { + config: { + headers: [{ key: 'content-type', value: 'text' }], + hasAuth: true, + }, + secrets: { + user: 'user', + password: 'pass', + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('succeeds with hasAuth=True', async () => { + const testFormData = { + config: { + headers: [{ key: 'content-type', value: 'text' }], + hasAuth: true, + }, + secrets: { + user: 'user', + password: 'pass', + }, + }; + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: { + config: { + headers: [{ key: 'content-type', value: 'text' }], + hasAuth: true, + authType: AuthType.Basic, + }, + secrets: { + user: 'user', + password: 'pass', + }, + __internal__: { + hasHeaders: true, + hasCA: false, + }, + }, + isValid: true, + }); + }); + }); + + it('succeeds with hasAuth=false', async () => { + const testFormData = { + config: { + ...defaultTestFormData.config, + hasAuth: false, + }, + }; + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: { + config: { + headers: [{ key: 'content-type', value: 'text' }], + hasAuth: false, + authType: null, + }, + __internal__: { + hasHeaders: true, + hasCA: false, + }, + }, + isValid: true, + }); + }); + }); + + it('succeeds without headers', async () => { + const testConfig = { + config: { + hasAuth: true, + authType: AuthType.Basic, + }, + secrets: { + user: 'user', + password: 'pass', + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: { + config: { + hasAuth: true, + authType: AuthType.Basic, + }, + secrets: { + user: 'user', + password: 'pass', + }, + __internal__: { + hasHeaders: false, + hasCA: false, + }, + }, + isValid: true, + }); + }); + }); + + it('succeeds with CA and verificationMode', async () => { + const testConfig = { + ...defaultTestFormData, + config: { + ...defaultTestFormData.config, + ca: Buffer.from('some binary string').toString('base64'), + verificationMode: 'full', + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: { + config: { + hasAuth: true, + authType: AuthType.Basic, + ca: Buffer.from('some binary string').toString('base64'), + verificationMode: 'full', + headers: [{ key: 'content-type', value: 'text' }], + }, + secrets: { + user: 'user', + password: 'pass', + }, + __internal__: { + hasHeaders: true, + hasCA: true, + }, + }, + isValid: true, + }); + }); + }); + + it('fails with hasCa=true and a missing CA', async () => { + const testConfig = { + ...defaultTestFormData, + config: { + ...defaultTestFormData.config, + verificationMode: 'full', + }, + __internal__: { + hasHeaders: true, + hasCA: true, + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: {}, + isValid: false, + }); + }); + }); + + it('succeeds with authType=SSL and a CRT and KEY', async () => { + const testConfig = { + config: { + ...defaultTestFormData.config, + authType: AuthType.SSL, + certType: SSLCertType.CRT, + }, + secrets: { + crt: Buffer.from('some binary string').toString('base64'), + key: Buffer.from('some binary string').toString('base64'), + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: { + config: { + hasAuth: true, + authType: AuthType.SSL, + certType: SSLCertType.CRT, + headers: [{ key: 'content-type', value: 'text' }], + }, + secrets: { + crt: Buffer.from('some binary string').toString('base64'), + key: Buffer.from('some binary string').toString('base64'), + }, + __internal__: { + hasHeaders: true, + hasCA: false, + }, + }, + isValid: true, + }); + }); + }); + + it('succeeds with authType=SSL and a PFX', async () => { + const testConfig = { + config: { + ...defaultTestFormData.config, + authType: AuthType.SSL, + certType: SSLCertType.PFX, + }, + secrets: { + pfx: Buffer.from('some binary string').toString('base64'), + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: { + config: { + hasAuth: true, + authType: AuthType.SSL, + certType: SSLCertType.PFX, + headers: [{ key: 'content-type', value: 'text' }], + }, + secrets: { + pfx: Buffer.from('some binary string').toString('base64'), + }, + __internal__: { + hasHeaders: true, + hasCA: false, + }, + }, + isValid: true, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/public/common/auth/auth_config.tsx b/x-pack/plugins/stack_connectors/public/common/auth/auth_config.tsx new file mode 100644 index 00000000000000..e4477be874ecb3 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/common/auth/auth_config.tsx @@ -0,0 +1,292 @@ +/* + * 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, { FunctionComponent, useEffect } from 'react'; + +import { + EuiButtonEmpty, + EuiButtonIcon, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { + UseArray, + UseField, + useFormContext, + useFormData, +} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { + ToggleField, + TextField, + CardRadioGroupField, + HiddenField, + FilePickerField, + SelectField, +} from '@kbn/es-ui-shared-plugin/static/forms/components'; + +import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; +import { AuthType, SSLCertType } from '../../../common/auth/constants'; +import { SSLCertFields } from './ssl_cert_fields'; +import { BasicAuthFields } from './basic_auth_fields'; +import * as i18n from './translations'; + +interface Props { + readOnly: boolean; + hideSSL?: boolean; +} + +const { emptyField } = fieldValidators; + +const VERIFICATION_MODE_DEFAULT = 'full'; + +export const AuthConfig: FunctionComponent = ({ readOnly, hideSSL }) => { + const { setFieldValue, getFieldDefaultValue } = useFormContext(); + const [{ config, __internal__ }] = useFormData({ + watch: [ + 'config.hasAuth', + 'config.authType', + 'config.certType', + 'config.verificationMode', + '__internal__.hasHeaders', + '__internal__.hasCA', + ], + }); + + const authType = config == null ? AuthType.Basic : config.authType; + const certType = config == null ? SSLCertType.CRT : config.certType; + const hasHeaders = __internal__ != null ? __internal__.hasHeaders : false; + const hasCA = __internal__ != null ? __internal__.hasCA : false; + const hasInitialCA = !!getFieldDefaultValue('config.ca'); + const hasHeadersDefaultValue = !!getFieldDefaultValue('config.headers'); + const authTypeDefaultValue = + getFieldDefaultValue('config.hasAuth') === false + ? null + : getFieldDefaultValue('config.authType') ?? AuthType.Basic; + const certTypeDefaultValue: SSLCertType = + getFieldDefaultValue('config.certType') ?? SSLCertType.CRT; + const hasCADefaultValue = + !!getFieldDefaultValue('config.ca') || + getFieldDefaultValue('config.verificationMode') === 'none'; + + useEffect(() => setFieldValue('config.hasAuth', Boolean(authType)), [authType, setFieldValue]); + + const hideSSLFields = hideSSL && authType !== AuthType.SSL; + + const authOptions = [ + { + value: null, + label: i18n.AUTHENTICATION_NONE, + 'data-test-subj': 'authNone', + }, + { + value: AuthType.Basic, + label: i18n.AUTHENTICATION_BASIC, + children: authType === AuthType.Basic && , + 'data-test-subj': 'authBasic', + }, + ]; + + if (!hideSSLFields) { + authOptions.push({ + value: AuthType.SSL, + label: i18n.AUTHENTICATION_SSL, + children: authType === AuthType.SSL && ( + + ), + 'data-test-subj': 'authSSL', + }); + } + + return ( + <> + + + +

{i18n.AUTHENTICATION_TITLE}

+ + + + + + + + + {hasHeaders && ( + + {({ items, addItem, removeItem }) => { + return ( + <> + +
{i18n.HEADERS_TITLE}
+
+ + {items.map((item) => ( + + + + + + + + + removeItem(item.id)} + iconType="minusInCircle" + aria-label={i18n.DELETE_BUTTON} + style={{ marginTop: '28px' }} + /> + + + ))} + + + {i18n.ADD_BUTTON} + + + + ); + }} +
+ )} + + {!hideSSLFields && ( + <> + + {hasCA && ( + <> + + + + {}, + }, + ], + }} + component={FilePickerField} + componentProps={{ + euiFieldProps: { + display: 'default', + 'data-test-subj': 'webhookCAInput', + accept: '.ca,.pem', + }, + }} + /> + + + + + + {hasInitialCA && ( + <> + + + + )} + + )} + + )} + + ); +}; diff --git a/x-pack/plugins/stack_connectors/public/common/auth/basic_auth_fields.test.tsx b/x-pack/plugins/stack_connectors/public/common/auth/basic_auth_fields.test.tsx new file mode 100644 index 00000000000000..6d740be7b270e6 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/common/auth/basic_auth_fields.test.tsx @@ -0,0 +1,112 @@ +/* + * 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 { BasicAuthFields } from './basic_auth_fields'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { AuthFormTestProvider } from '../../connector_types/lib/test_utils'; + +describe('BasicAuthFields', () => { + const onSubmit = jest.fn(); + + it('renders all fields', async () => { + const testFormData = { + secrets: { + user: 'user', + password: 'pass', + }, + }; + + render( + + + + ); + + expect(await screen.findByTestId('basicAuthFields')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookUserInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookPasswordInput')).toBeInTheDocument(); + }); + + describe('Validation', () => { + const defaultTestFormData = { + secrets: { + user: 'user', + password: 'pass', + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('validation succeeds with correct fields', async () => { + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: { + secrets: { + user: 'user', + password: 'pass', + }, + }, + isValid: true, + }); + }); + }); + + it('validates correctly missing user', async () => { + const testConfig = { + secrets: { + user: '', + password: 'password', + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false }); + }); + }); + + it('validates correctly missing password', async () => { + const testConfig = { + secrets: { + user: 'user', + password: '', + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false }); + }); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/public/common/auth/basic_auth_fields.tsx b/x-pack/plugins/stack_connectors/public/common/auth/basic_auth_fields.tsx new file mode 100644 index 00000000000000..5b26f0e888e2b8 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/common/auth/basic_auth_fields.tsx @@ -0,0 +1,60 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { Field, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; + +import * as i18n from './translations'; + +const { emptyField } = fieldValidators; + +interface BasicAuthProps { + readOnly: boolean; +} + +export const BasicAuthFields: React.FC = ({ readOnly }) => ( + + + + + + + + +); diff --git a/x-pack/plugins/stack_connectors/public/common/auth/ssl_cert_fields.test.tsx b/x-pack/plugins/stack_connectors/public/common/auth/ssl_cert_fields.test.tsx new file mode 100644 index 00000000000000..9a39926b21324e --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/common/auth/ssl_cert_fields.test.tsx @@ -0,0 +1,223 @@ +/* + * 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 { SSLCertFields } from './ssl_cert_fields'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { SSLCertType } from '../../../common/auth/constants'; +import { AuthFormTestProvider } from '../../connector_types/lib/test_utils'; + +const certTypeDefaultValue: SSLCertType = SSLCertType.CRT; + +describe('SSLCertFields', () => { + const onSubmit = jest.fn(); + + it('renders all fields for certType=CRT', async () => { + render( + + + + ); + + expect(await screen.findByTestId('sslCertFields')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookSSLPassphraseInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCertTypeTabs')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookSSLCRTInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookSSLKEYInput')).toBeInTheDocument(); + }); + + it('renders all fields for certType=PFX', async () => { + render( + + + + ); + + expect(await screen.findByTestId('sslCertFields')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookSSLPassphraseInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCertTypeTabs')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookSSLPFXInput')).toBeInTheDocument(); + }); + + describe('Validation', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('validates correctly with a PFX', async () => { + const testConfig = { + config: { + certType: SSLCertType.PFX, + }, + secrets: { + pfx: Buffer.from('some binary string').toString('base64'), + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: { + config: { + certType: SSLCertType.PFX, + }, + secrets: { + pfx: Buffer.from('some binary string').toString('base64'), + }, + }, + isValid: true, + }); + }); + }); + + it('validates correctly a missing PFX', async () => { + const testConfig = { + config: { + certType: SSLCertType.PFX, + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: {}, + isValid: false, + }); + }); + }); + + it('validates correctly with a CRT and KEY', async () => { + const testConfig = { + config: { + certType: SSLCertType.CRT, + }, + secrets: { + crt: Buffer.from('some binary string').toString('base64'), + key: Buffer.from('some binary string').toString('base64'), + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: { + config: { + certType: SSLCertType.CRT, + }, + secrets: { + crt: Buffer.from('some binary string').toString('base64'), + key: Buffer.from('some binary string').toString('base64'), + }, + }, + isValid: true, + }); + }); + }); + + it('validates correctly with a CRT but a missing KEY', async () => { + const testConfig = { + config: { + certType: SSLCertType.CRT, + }, + secrets: { + crt: Buffer.from('some binary string').toString('base64'), + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: {}, + isValid: false, + }); + }); + }); + + it('validates correctly with a KEY but a missing CRT', async () => { + const testConfig = { + config: { + certType: SSLCertType.CRT, + }, + secrets: { + key: Buffer.from('some binary string').toString('base64'), + }, + }; + + render( + + + + ); + + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => { + expect(onSubmit).toHaveBeenCalledWith({ + data: {}, + isValid: false, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/public/common/auth/ssl_cert_fields.tsx b/x-pack/plugins/stack_connectors/public/common/auth/ssl_cert_fields.tsx new file mode 100644 index 00000000000000..cf9dc672dde330 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/common/auth/ssl_cert_fields.tsx @@ -0,0 +1,138 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui'; +import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; +import { FilePickerField } from '@kbn/es-ui-shared-plugin/static/forms/components'; + +import { SSLCertType } from '../../../common/auth/constants'; +import * as i18n from './translations'; + +const { emptyField } = fieldValidators; + +interface BasicAuthProps { + readOnly: boolean; + certTypeDefaultValue: SSLCertType; + certType: SSLCertType; +} + +export const SSLCertFields: React.FC = ({ + readOnly, + certTypeDefaultValue, + certType, +}) => ( + + + + + ( + + field.setValue(SSLCertType.CRT)} + isSelected={field.value === SSLCertType.CRT} + > + {i18n.CERT_TYPE_CRT_KEY} + + field.setValue(SSLCertType.PFX)} + isSelected={field.value === SSLCertType.PFX} + > + {i18n.CERT_TYPE_PFX} + + + )} + /> + + {certType === SSLCertType.CRT && ( + + + + + + + + + )} + {certType === SSLCertType.PFX && ( + + )} + + +); diff --git a/x-pack/plugins/stack_connectors/public/common/auth/translations.ts b/x-pack/plugins/stack_connectors/public/common/auth/translations.ts new file mode 100644 index 00000000000000..88d97bef6364d7 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/common/auth/translations.ts @@ -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 { i18n } from '@kbn/i18n'; + +export const AUTHENTICATION_TITLE = i18n.translate( + 'xpack.stackConnectors.components.auth.authenticationTitle', + { + defaultMessage: 'Authentication', + } +); + +export const AUTHENTICATION_NONE = i18n.translate( + 'xpack.stackConnectors.components.auth.authenticationMethodNoneLabel', + { + defaultMessage: 'None', + } +); + +export const AUTHENTICATION_BASIC = i18n.translate( + 'xpack.stackConnectors.components.auth.authenticationMethodBasicLabel', + { + defaultMessage: 'Basic authentication', + } +); + +export const AUTHENTICATION_SSL = i18n.translate( + 'xpack.stackConnectors.components.auth.authenticationMethodSSLLabel', + { + defaultMessage: 'SSL authentication', + } +); + +export const USERNAME = i18n.translate('xpack.stackConnectors.components.auth.userTextFieldLabel', { + defaultMessage: 'Username', +}); + +export const PASSWORD = i18n.translate( + 'xpack.stackConnectors.components.auth.passwordTextFieldLabel', + { + defaultMessage: 'Password', + } +); + +export const USERNAME_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.auth.error.requiredAuthUserNameText', + { + defaultMessage: 'Username is required.', + } +); + +export const PASSWORD_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.auth.error.requiredAuthPasswordText', + { + defaultMessage: 'Password is required.', + } +); + +export const CERT_TYPE_CRT_KEY = i18n.translate( + 'xpack.stackConnectors.components.auth.certTypeCrtKeyLabel', + { + defaultMessage: 'CRT and KEY file', + } +); +export const CERT_TYPE_PFX = i18n.translate( + 'xpack.stackConnectors.components.auth.certTypePfxLabel', + { + defaultMessage: 'PFX file', + } +); + +export const CRT_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.auth.error.requiredCRTText', + { + defaultMessage: 'CRT file is required.', + } +); + +export const KEY_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.auth.error.requiredKEYText', + { + defaultMessage: 'KEY file is required.', + } +); + +export const PFX_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.auth.error.requiredPFXText', + { + defaultMessage: 'PFX file is required.', + } +); + +export const HEADERS_SWITCH = i18n.translate( + 'xpack.stackConnectors.components.auth.viewHeadersSwitch', + { + defaultMessage: 'Add HTTP header', + } +); + +export const HEADERS_TITLE = i18n.translate( + 'xpack.stackConnectors.components.auth.httpHeadersTitle', + { + defaultMessage: 'Headers in use', + } +); + +export const KEY_LABEL = i18n.translate('xpack.stackConnectors.components.auth.keyTextFieldLabel', { + defaultMessage: 'Key', +}); + +export const VALUE_LABEL = i18n.translate( + 'xpack.stackConnectors.components.auth.valueTextFieldLabel', + { + defaultMessage: 'Value', + } +); + +export const ADD_BUTTON = i18n.translate('xpack.stackConnectors.components.auth.addHeaderButton', { + defaultMessage: 'Add', +}); + +export const DELETE_BUTTON = i18n.translate( + 'xpack.stackConnectors.components.auth.deleteHeaderButton', + { + defaultMessage: 'Delete', + description: 'Delete HTTP header', + } +); + +export const CA_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.auth.error.requiredCAText', + { + defaultMessage: 'CA file is required.', + } +); + +export const ADD_CA_LABEL = i18n.translate( + 'xpack.stackConnectors.components.auth.viewCertificateAuthoritySwitch', + { + defaultMessage: 'Add certificate authority', + } +); + +export const VERIFICATION_MODE_LABEL = i18n.translate( + 'xpack.stackConnectors.components.auth.verificationModeFieldLabel', + { defaultMessage: 'Verification mode' } +); + +export const EDIT_CA_CALLOUT = i18n.translate( + 'xpack.stackConnectors.components.auth.editCACallout', + { + defaultMessage: + 'This connector has an existing certificate authority file. Upload a new one to replace it.', + } +); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/auth.tsx b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/auth.tsx index f27ad80ae942c6..3d7b5bf27e173b 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/auth.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/auth.tsx @@ -6,25 +6,10 @@ */ import React, { FunctionComponent } from 'react'; -import { - EuiButtonEmpty, - EuiButtonIcon, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; -import { - FIELD_TYPES, - UseArray, - UseField, - useFormContext, - useFormData, -} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { Field, TextField, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components'; -import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import * as i18n from '../translations'; -const { emptyField } = fieldValidators; + +import { EuiSpacer } from '@elastic/eui'; + +import { AuthConfig } from '../../../common/auth/auth_config'; interface Props { display: boolean; @@ -32,158 +17,10 @@ interface Props { } export const AuthStep: FunctionComponent = ({ display, readOnly }) => { - const { getFieldDefaultValue } = useFormContext(); - const [{ config, __internal__ }] = useFormData({ - watch: ['config.hasAuth', '__internal__.hasHeaders'], - }); - - const hasHeadersDefaultValue = !!getFieldDefaultValue('config.headers'); - - const hasAuth = config == null ? true : config.hasAuth; - const hasHeaders = __internal__ != null ? __internal__.hasHeaders : false; - return ( - - - -

{i18n.AUTH_TITLE}

-
- - -
-
- {hasAuth ? ( - - - - - - - - - ) : null} - - - - {hasHeaders ? ( - - {({ items, addItem, removeItem }) => { - return ( - <> - -
{i18n.HEADERS_TITLE}
-
- - {items.map((item) => ( - - - - - - - - - removeItem(item.id)} - iconType="minusInCircle" - aria-label={i18n.DELETE_BUTTON} - style={{ marginTop: '28px' }} - /> - - - ))} - - - {i18n.ADD_BUTTON} - - - - ); - }} -
- ) : null} + +
); }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts index 02b45786c362f9..5986126d17adc0 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts @@ -112,20 +112,6 @@ export const MISSING_VARIABLES = (variables: string[]) => values: { variableCount: variables.length, variables: variables.join(', ') }, }); -export const USERNAME_REQUIRED = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.error.requiredAuthUserNameText', - { - defaultMessage: 'Username is required.', - } -); - -export const PASSWORD_REQUIRED = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.error.requiredAuthPasswordText', - { - defaultMessage: 'Password is required.', - } -); - export const SUMMARY_REQUIRED = i18n.translate( 'xpack.stackConnectors.components.casesWebhook.error.requiredWebhookSummaryText', { @@ -133,35 +119,6 @@ export const SUMMARY_REQUIRED = i18n.translate( } ); -export const KEY_LABEL = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.keyTextFieldLabel', - { - defaultMessage: 'Key', - } -); - -export const VALUE_LABEL = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.valueTextFieldLabel', - { - defaultMessage: 'Value', - } -); - -export const ADD_BUTTON = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.addHeaderButton', - { - defaultMessage: 'Add', - } -); - -export const DELETE_BUTTON = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.deleteHeaderButton', - { - defaultMessage: 'Delete', - description: 'Delete HTTP header', - } -); - export const CREATE_INCIDENT_METHOD = i18n.translate( 'xpack.stackConnectors.components.casesWebhook.createIncidentMethodTextFieldLabel', { @@ -338,41 +295,6 @@ export const HAS_AUTH = i18n.translate( } ); -export const USERNAME = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.userTextFieldLabel', - { - defaultMessage: 'Username', - } -); - -export const PASSWORD = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.passwordTextFieldLabel', - { - defaultMessage: 'Password', - } -); - -export const HEADERS_SWITCH = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.viewHeadersSwitch', - { - defaultMessage: 'Add HTTP header', - } -); - -export const HEADERS_TITLE = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.httpHeadersTitle', - { - defaultMessage: 'Headers in use', - } -); - -export const AUTH_TITLE = i18n.translate( - 'xpack.stackConnectors.components.casesWebhook.authenticationLabel', - { - defaultMessage: 'Authentication', - } -); - export const STEP_1 = i18n.translate('xpack.stackConnectors.components.casesWebhook.step1', { defaultMessage: 'Set up connector', }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.test.tsx index b06f7accae3070..66d15550b7b757 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.test.tsx @@ -7,8 +7,9 @@ import React from 'react'; import CasesWebhookActionConnectorFields from './webhook_connectors'; -import { ConnectorFormTestProvider, waitForComponentToUpdate } from '../lib/test_utils'; -import { act, render } from '@testing-library/react'; +import { ConnectorFormTestProvider } from '../lib/test_utils'; +import { render, screen, waitFor } from '@testing-library/react'; +import { AuthType } from '../../../common/auth/constants'; import userEvent from '@testing-library/user-event'; import * as i18n from './translations'; @@ -27,6 +28,7 @@ jest.mock('@kbn/triggers-actions-ui-plugin/public', () => { const invalidJsonTitle = `{"fields":{"summary":"wrong","description":{{{case.description}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}`; const invalidJsonBoth = `{"fields":{"summary":"wrong","description":"wrong","project":{"key":"ROC"},"issuetype":{"id":"10024"}}}`; const config = { + authType: AuthType.Basic, createCommentJson: '{"body":{{{case.comment}}}}', createCommentMethod: 'post', createCommentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}/comment', @@ -59,8 +61,8 @@ const actionConnector = { }; describe('CasesWebhookActionConnectorFields renders', () => { - test('All inputs are properly rendered', async () => { - const { getByTestId } = render( + it('All inputs are properly rendered', async () => { + render( { /> ); - await waitForComponentToUpdate(); - expect(getByTestId('webhookUserInput')).toBeInTheDocument(); - expect(getByTestId('webhookPasswordInput')).toBeInTheDocument(); - expect(getByTestId('webhookHeadersKeyInput')).toBeInTheDocument(); - expect(getByTestId('webhookHeadersValueInput')).toBeInTheDocument(); - expect(getByTestId('webhookCreateMethodSelect')).toBeInTheDocument(); - expect(getByTestId('webhookCreateUrlText')).toBeInTheDocument(); - expect(getByTestId('webhookCreateIncidentJson')).toBeInTheDocument(); - expect(getByTestId('createIncidentResponseKeyText')).toBeInTheDocument(); - expect(getByTestId('getIncidentUrlInput')).toBeInTheDocument(); - expect(getByTestId('getIncidentResponseExternalTitleKeyText')).toBeInTheDocument(); - expect(getByTestId('viewIncidentUrlInput')).toBeInTheDocument(); - expect(getByTestId('webhookUpdateMethodSelect')).toBeInTheDocument(); - expect(getByTestId('updateIncidentUrlInput')).toBeInTheDocument(); - expect(getByTestId('webhookUpdateIncidentJson')).toBeInTheDocument(); - expect(getByTestId('webhookCreateCommentMethodSelect')).toBeInTheDocument(); - expect(getByTestId('createCommentUrlInput')).toBeInTheDocument(); - expect(getByTestId('webhookCreateCommentJson')).toBeInTheDocument(); + + expect(await screen.findByTestId('authNone')).toBeInTheDocument(); + expect(await screen.findByTestId('authBasic')).toBeInTheDocument(); + // expect(await screen.findByTestId('authSSL')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookUserInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookPasswordInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookHeadersKeyInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookHeadersValueInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCreateMethodSelect')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCreateUrlText')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCreateIncidentJson')).toBeInTheDocument(); + expect(await screen.findByTestId('createIncidentResponseKeyText')).toBeInTheDocument(); + expect(await screen.findByTestId('getIncidentUrlInput')).toBeInTheDocument(); + expect( + await screen.findByTestId('getIncidentResponseExternalTitleKeyText') + ).toBeInTheDocument(); + expect(await screen.findByTestId('viewIncidentUrlInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookUpdateMethodSelect')).toBeInTheDocument(); + expect(await screen.findByTestId('updateIncidentUrlInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookUpdateIncidentJson')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCreateCommentMethodSelect')).toBeInTheDocument(); + expect(await screen.findByTestId('createCommentUrlInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCreateCommentJson')).toBeInTheDocument(); }); - test('Toggles work properly', async () => { - const { getByTestId, queryByTestId } = render( + + it('connector auth toggles work as expected', async () => { + render( { /> ); - await waitForComponentToUpdate(); - expect(getByTestId('hasAuthToggle')).toHaveAttribute('aria-checked', 'true'); - await act(async () => { - userEvent.click(getByTestId('hasAuthToggle')); - }); - expect(getByTestId('hasAuthToggle')).toHaveAttribute('aria-checked', 'false'); - expect(queryByTestId('webhookUserInput')).not.toBeInTheDocument(); - expect(queryByTestId('webhookPasswordInput')).not.toBeInTheDocument(); - expect(getByTestId('webhookViewHeadersSwitch')).toHaveAttribute('aria-checked', 'true'); - await act(async () => { - userEvent.click(getByTestId('webhookViewHeadersSwitch')); - }); - expect(getByTestId('webhookViewHeadersSwitch')).toHaveAttribute('aria-checked', 'false'); - expect(queryByTestId('webhookHeadersKeyInput')).not.toBeInTheDocument(); - expect(queryByTestId('webhookHeadersValueInput')).not.toBeInTheDocument(); + const authNoneToggle = await screen.findByTestId('authNone'); + + expect(authNoneToggle).toBeInTheDocument(); + expect(await screen.findByTestId('authBasic')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookUserInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookPasswordInput')).toBeInTheDocument(); + + userEvent.click(authNoneToggle); + + expect(screen.queryByTestId('webhookUserInput')).not.toBeInTheDocument(); + expect(screen.queryByTestId('webhookPasswordInput')).not.toBeInTheDocument(); + + expect(await screen.findByTestId('webhookViewHeadersSwitch')).toHaveAttribute( + 'aria-checked', + 'true' + ); + userEvent.click(await screen.findByTestId('webhookViewHeadersSwitch')); + expect(await screen.findByTestId('webhookViewHeadersSwitch')).toHaveAttribute( + 'aria-checked', + 'false' + ); + expect(screen.queryByTestId('webhookHeadersKeyInput')).not.toBeInTheDocument(); + expect(screen.queryByTestId('webhookHeadersValueInput')).not.toBeInTheDocument(); }); + describe('Step Validation', () => { - test('Steps work correctly when all fields valid', async () => { - const { queryByTestId, getByTestId } = render( + it('Steps work correctly when all fields valid', async () => { + render( { /> ); - await waitForComponentToUpdate(); - expect(getByTestId('horizontalStep1-current')).toBeInTheDocument(); - expect(getByTestId('horizontalStep2-incomplete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep3-incomplete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep4-incomplete')).toBeInTheDocument(); - expect(getByTestId('authStep')).toHaveAttribute('style', 'display: block;'); - expect(getByTestId('createStep')).toHaveAttribute('style', 'display: none;'); - expect(getByTestId('getStep')).toHaveAttribute('style', 'display: none;'); - expect(getByTestId('updateStep')).toHaveAttribute('style', 'display: none;'); - expect(queryByTestId('casesWebhookBack')).not.toBeInTheDocument(); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - expect(getByTestId('horizontalStep1-complete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep2-current')).toBeInTheDocument(); - expect(getByTestId('horizontalStep3-incomplete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep4-incomplete')).toBeInTheDocument(); - expect(getByTestId('authStep')).toHaveAttribute('style', 'display: none;'); - expect(getByTestId('createStep')).toHaveAttribute('style', 'display: block;'); - expect(getByTestId('getStep')).toHaveAttribute('style', 'display: none;'); - expect(getByTestId('updateStep')).toHaveAttribute('style', 'display: none;'); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - expect(getByTestId('horizontalStep1-complete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep2-complete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep3-current')).toBeInTheDocument(); - expect(getByTestId('horizontalStep4-incomplete')).toBeInTheDocument(); - expect(getByTestId('authStep')).toHaveAttribute('style', 'display: none;'); - expect(getByTestId('createStep')).toHaveAttribute('style', 'display: none;'); - expect(getByTestId('getStep')).toHaveAttribute('style', 'display: block;'); - expect(getByTestId('updateStep')).toHaveAttribute('style', 'display: none;'); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - expect(getByTestId('horizontalStep1-complete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep2-complete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep3-complete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep4-current')).toBeInTheDocument(); - expect(getByTestId('authStep')).toHaveAttribute('style', 'display: none;'); - expect(getByTestId('createStep')).toHaveAttribute('style', 'display: none;'); - expect(getByTestId('getStep')).toHaveAttribute('style', 'display: none;'); - expect(getByTestId('updateStep')).toHaveAttribute('style', 'display: block;'); - expect(queryByTestId('casesWebhookNext')).not.toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep1-current')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep2-incomplete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep3-incomplete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep4-incomplete')).toBeInTheDocument(); + expect(await screen.findByTestId('authStep')).toHaveAttribute('style', 'display: block;'); + expect(await screen.findByTestId('createStep')).toHaveAttribute('style', 'display: none;'); + expect(await screen.findByTestId('getStep')).toHaveAttribute('style', 'display: none;'); + expect(await screen.findByTestId('updateStep')).toHaveAttribute('style', 'display: none;'); + expect(screen.queryByTestId('casesWebhookBack')).not.toBeInTheDocument(); + + userEvent.click(await screen.findByTestId('casesWebhookNext')); + + expect(await screen.findByTestId('horizontalStep1-complete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep2-current')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep3-incomplete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep4-incomplete')).toBeInTheDocument(); + expect(await screen.findByTestId('authStep')).toHaveAttribute('style', 'display: none;'); + expect(await screen.findByTestId('createStep')).toHaveAttribute('style', 'display: block;'); + expect(await screen.findByTestId('getStep')).toHaveAttribute('style', 'display: none;'); + expect(await screen.findByTestId('updateStep')).toHaveAttribute('style', 'display: none;'); + + userEvent.click(await screen.findByTestId('casesWebhookNext')); + + expect(await screen.findByTestId('horizontalStep1-complete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep2-complete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep3-current')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep4-incomplete')).toBeInTheDocument(); + expect(await screen.findByTestId('authStep')).toHaveAttribute('style', 'display: none;'); + expect(await screen.findByTestId('createStep')).toHaveAttribute('style', 'display: none;'); + expect(await screen.findByTestId('getStep')).toHaveAttribute('style', 'display: block;'); + expect(await screen.findByTestId('updateStep')).toHaveAttribute('style', 'display: none;'); + + userEvent.click(await screen.findByTestId('casesWebhookNext')); + + expect(await screen.findByTestId('horizontalStep1-complete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep2-complete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep3-complete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep4-current')).toBeInTheDocument(); + expect(await screen.findByTestId('authStep')).toHaveAttribute('style', 'display: none;'); + expect(await screen.findByTestId('createStep')).toHaveAttribute('style', 'display: none;'); + expect(await screen.findByTestId('getStep')).toHaveAttribute('style', 'display: none;'); + expect(await screen.findByTestId('updateStep')).toHaveAttribute('style', 'display: block;'); + expect(screen.queryByTestId('casesWebhookNext')).not.toBeInTheDocument(); }); - test('Step 1 is properly validated', async () => { + + it('Step 1 is properly validated', async () => { const incompleteActionConnector = { ...actionConnector, secrets: { @@ -179,7 +196,7 @@ describe('CasesWebhookActionConnectorFields renders', () => { password: '', }, }; - const { getByTestId } = render( + render( { /> ); - await waitForComponentToUpdate(); - expect(getByTestId('horizontalStep1-current')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep1-current')).toBeInTheDocument(); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - await waitForComponentToUpdate(); + userEvent.click(await screen.findByTestId('casesWebhookNext')); - expect(getByTestId('horizontalStep1-danger')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep1-danger')).toBeInTheDocument(); - await act(async () => { - userEvent.click(getByTestId('hasAuthToggle')); - userEvent.click(getByTestId('webhookViewHeadersSwitch')); - }); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); + userEvent.click(await screen.findByTestId('authNone')); + userEvent.click(await screen.findByTestId('webhookViewHeadersSwitch')); + userEvent.click(await screen.findByTestId('casesWebhookNext')); - expect(getByTestId('horizontalStep1-complete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep2-current')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep1-complete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep2-current')).toBeInTheDocument(); }); - test('Step 2 is properly validated', async () => { + + it('Step 2 is properly validated', async () => { const incompleteActionConnector = { ...actionConnector, config: { @@ -218,7 +228,7 @@ describe('CasesWebhookActionConnectorFields renders', () => { createIncidentUrl: undefined, }, }; - const { getByText, getByTestId } = render( + render( { /> ); - await waitForComponentToUpdate(); - expect(getByTestId('horizontalStep2-incomplete')).toBeInTheDocument(); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - getByText(i18n.CREATE_URL_REQUIRED); - expect(getByTestId('horizontalStep2-danger')).toBeInTheDocument(); - await act(async () => { - await userEvent.type( - getByTestId('webhookCreateUrlText'), - `{selectall}{backspace}${config.createIncidentUrl}`, - { - delay: 10, - } - ); - }); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - expect(getByTestId('horizontalStep2-complete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep3-current')).toBeInTheDocument(); - await act(async () => { - userEvent.click(getByTestId('horizontalStep2-complete')); - }); - expect(getByTestId('horizontalStep2-current')).toBeInTheDocument(); - expect(getByTestId('horizontalStep3-incomplete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep2-incomplete')).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('casesWebhookNext')); + userEvent.click(await screen.findByTestId('casesWebhookNext')); + expect(await screen.findByText(i18n.CREATE_URL_REQUIRED)).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep2-danger')).toBeInTheDocument(); + await userEvent.type( + await screen.findByTestId('webhookCreateUrlText'), + `{selectall}{backspace}${config.createIncidentUrl}`, + { + delay: 10, + } + ); + + userEvent.click(await screen.findByTestId('casesWebhookNext')); + + expect(await screen.findByTestId('horizontalStep2-complete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep3-current')).toBeInTheDocument(); + + userEvent.click(await screen.findByTestId('horizontalStep2-complete')); + + expect(await screen.findByTestId('horizontalStep2-current')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep3-incomplete')).toBeInTheDocument(); }); - test('Step 3 is properly validated', async () => { + + it('Step 3 is properly validated', async () => { const incompleteActionConnector = { ...actionConnector, config: { @@ -265,7 +269,7 @@ describe('CasesWebhookActionConnectorFields renders', () => { getIncidentResponseExternalTitleKey: undefined, }, }; - const { getByText, getByTestId } = render( + render( { /> ); - await waitForComponentToUpdate(); - expect(getByTestId('horizontalStep2-incomplete')).toBeInTheDocument(); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - getByText(i18n.GET_RESPONSE_EXTERNAL_TITLE_KEY_REQUIRED); - expect(getByTestId('horizontalStep3-danger')).toBeInTheDocument(); - await act(async () => { - await userEvent.type( - getByTestId('getIncidentResponseExternalTitleKeyText'), - `{selectall}{backspace}${config.getIncidentResponseExternalTitleKey}`, - { - delay: 10, - } - ); - }); - await act(async () => { - userEvent.click(getByTestId('casesWebhookNext')); - }); - expect(getByTestId('horizontalStep3-complete')).toBeInTheDocument(); - expect(getByTestId('horizontalStep4-current')).toBeInTheDocument(); - await act(async () => { - userEvent.click(getByTestId('horizontalStep3-complete')); - }); - expect(getByTestId('horizontalStep3-current')).toBeInTheDocument(); - expect(getByTestId('horizontalStep4-incomplete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep2-incomplete')).toBeInTheDocument(); + + userEvent.click(await screen.findByTestId('casesWebhookNext')); + userEvent.click(await screen.findByTestId('casesWebhookNext')); + userEvent.click(await screen.findByTestId('casesWebhookNext')); + + expect( + await screen.findByText(i18n.GET_RESPONSE_EXTERNAL_TITLE_KEY_REQUIRED) + ).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep3-danger')).toBeInTheDocument(); + + await userEvent.type( + await screen.findByTestId('getIncidentResponseExternalTitleKeyText'), + `{selectall}{backspace}${config.getIncidentResponseExternalTitleKey}`, + { + delay: 10, + } + ); + + userEvent.click(await screen.findByTestId('casesWebhookNext')); + + expect(await screen.findByTestId('horizontalStep3-complete')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep4-current')).toBeInTheDocument(); + + userEvent.click(await screen.findByTestId('horizontalStep3-complete')); + + expect(await screen.findByTestId('horizontalStep3-current')).toBeInTheDocument(); + expect(await screen.findByTestId('horizontalStep4-incomplete')).toBeInTheDocument(); }); // step 4 is not validated like the others since it is the last step @@ -346,7 +346,7 @@ describe('CasesWebhookActionConnectorFields renders', () => { ]; it('connector validation succeeds when connector config is valid', async () => { - const { getByTestId } = render( + render( { ); - await act(async () => { - userEvent.click(getByTestId('form-test-provide-submit')); - }); + userEvent.click(await screen.findByTestId('form-test-provide-submit')); const { isPreconfigured, ...rest } = actionConnector; - - expect(onSubmit).toBeCalledWith({ - data: { - ...rest, - __internal__: { - hasHeaders: true, + await waitFor(() => + expect(onSubmit).toBeCalledWith({ + data: { + ...rest, + __internal__: { + // hasCA: false, + hasHeaders: true, + }, }, - }, - isValid: true, - }); + isValid: true, + }) + ); }); it('connector validation succeeds when auth=false', async () => { @@ -381,7 +381,7 @@ describe('CasesWebhookActionConnectorFields renders', () => { }, }; - const { getByTestId } = render( + render( { ); - await act(async () => { - userEvent.click(getByTestId('form-test-provide-submit')); - }); + userEvent.click(await screen.findByTestId('form-test-provide-submit')); const { isPreconfigured, secrets, ...rest } = actionConnector; - expect(onSubmit).toBeCalledWith({ - data: { - ...rest, - config: { - ...actionConnector.config, - hasAuth: false, - }, - __internal__: { - hasHeaders: true, + await waitFor(() => + expect(onSubmit).toBeCalledWith({ + data: { + ...rest, + config: { + ...actionConnector.config, + hasAuth: false, + authType: null, + }, + __internal__: { + // hasCA: false, + hasHeaders: true, + }, }, - }, - isValid: true, - }); + isValid: true, + }) + ); }); it('connector validation succeeds without headers', async () => { @@ -420,7 +422,7 @@ describe('CasesWebhookActionConnectorFields renders', () => { }, }; - const { getByTestId } = render( + render( { ); - await act(async () => { - userEvent.click(getByTestId('form-test-provide-submit')); - }); + userEvent.click(await screen.findByTestId('form-test-provide-submit')); const { isPreconfigured, ...rest } = actionConnector; const { headers, ...rest2 } = actionConnector.config; - expect(onSubmit).toBeCalledWith({ - data: { - ...rest, - config: rest2, - __internal__: { - hasHeaders: false, + await waitFor(() => + expect(onSubmit).toBeCalledWith({ + data: { + ...rest, + config: rest2, + __internal__: { + // hasCA: false, + hasHeaders: false, + }, }, - }, - isValid: true, - }); + isValid: true, + }) + ); }); it('validates correctly if the method is empty', async () => { @@ -457,7 +460,7 @@ describe('CasesWebhookActionConnectorFields renders', () => { }, }; - const res = render( + render( { ); - await act(async () => { - userEvent.click(res.getByTestId('form-test-provide-submit')); - }); - - expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false }); + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false })); }); it.each(tests)('validates correctly %p', async (field, value) => { @@ -483,7 +483,7 @@ describe('CasesWebhookActionConnectorFields renders', () => { }, }; - const res = render( + render( { ); - await act(async () => { - await userEvent.type(res.getByTestId(field), `{selectall}{backspace}${value}`, { - delay: 10, - }); + await userEvent.type(await screen.findByTestId(field), `{selectall}{backspace}${value}`, { + delay: 10, }); - await act(async () => { - userEvent.click(res.getByTestId('form-test-provide-submit')); - }); + userEvent.click(await screen.findByTestId('form-test-provide-submit')); - expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false }); + await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false })); }); it.each(mustacheTests)( @@ -518,7 +514,7 @@ describe('CasesWebhookActionConnectorFields renders', () => { }, }; - const res = render( + render( { ); - await act(async () => { - userEvent.click(res.getByTestId('form-test-provide-submit')); - }); - - expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false }); - expect(res.getByText(i18n.MISSING_VARIABLES(missingVariables))).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('form-test-provide-submit')); + await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false })); + expect( + await screen.findByText(i18n.MISSING_VARIABLES(missingVariables)) + ).toBeInTheDocument(); } ); }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx index 6503cc77634690..29e0a8dd55b4bf 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx @@ -52,6 +52,21 @@ const ConnectorFormTestProviderComponent: React.FC = ({ + children, + defaultValue, + onSubmit, +}) => { + return ( + + {children} + + ); +}; + +AuthFormTestProviderComponent.displayName = 'AuthFormTestProvider'; +export const AuthFormTestProvider = React.memo(AuthFormTestProviderComponent); + const FormTestProviderComponent: React.FC = ({ children, defaultValue, diff --git a/x-pack/plugins/stack_connectors/public/connector_types/webhook/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/webhook/translations.ts index d0802fe5494b5c..c6db3f0f1ef1b5 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/webhook/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/webhook/translations.ts @@ -14,13 +14,6 @@ export const METHOD_LABEL = i18n.translate( } ); -export const HAS_AUTH_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.hasAuthSwitchLabel', - { - defaultMessage: 'Require authentication for this webhook', - } -); - export const URL_LABEL = i18n.translate( 'xpack.stackConnectors.components.webhook.urlTextFieldLabel', { @@ -28,62 +21,6 @@ export const URL_LABEL = i18n.translate( } ); -export const USERNAME_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.userTextFieldLabel', - { - defaultMessage: 'Username', - } -); - -export const PASSWORD_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.passwordTextFieldLabel', - { - defaultMessage: 'Password', - } -); - -export const PASSPHRASE_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.passphraseTextFieldLabel', - { - defaultMessage: 'Passphrase', - } -); - -export const ADD_HEADERS_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.viewHeadersSwitch', - { - defaultMessage: 'Add HTTP header', - } -); - -export const HEADER_KEY_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.headerKeyTextFieldLabel', - { - defaultMessage: 'Key', - } -); - -export const REMOVE_ITEM_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.removeHeaderIconLabel', - { - defaultMessage: 'Key', - } -); - -export const ADD_HEADER_BTN = i18n.translate( - 'xpack.stackConnectors.components.webhook.addHeaderButtonLabel', - { - defaultMessage: 'Add header', - } -); - -export const HEADER_VALUE_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.headerValueTextFieldLabel', - { - defaultMessage: 'Value', - } -); - export const URL_INVALID = i18n.translate( 'xpack.stackConnectors.components.webhook.error.invalidUrlTextField', { @@ -98,105 +35,9 @@ export const METHOD_REQUIRED = i18n.translate( } ); -export const USERNAME_REQUIRED = i18n.translate( - 'xpack.stackConnectors.components.webhook.error.requiredAuthUserNameText', - { - defaultMessage: 'Username is required.', - } -); - export const BODY_REQUIRED = i18n.translate( 'xpack.stackConnectors.components.webhook.error.requiredWebhookBodyText', { defaultMessage: 'Body is required.', } ); - -export const PASSWORD_REQUIRED = i18n.translate( - 'xpack.stackConnectors.components.webhook.error.requiredWebhookPasswordText', - { - defaultMessage: 'Password is required.', - } -); - -export const AUTHENTICATION_NONE = i18n.translate( - 'xpack.stackConnectors.components.webhook.authenticationMethodNoneLabel', - { - defaultMessage: 'None', - } -); - -export const AUTHENTICATION_BASIC = i18n.translate( - 'xpack.stackConnectors.components.webhook.authenticationMethodBasicLabel', - { - defaultMessage: 'Basic authentication', - } -); - -export const AUTHENTICATION_SSL = i18n.translate( - 'xpack.stackConnectors.components.webhook.authenticationMethodSSLLabel', - { - defaultMessage: 'SSL authentication', - } -); - -export const CERT_TYPE_CRT_KEY = i18n.translate( - 'xpack.stackConnectors.components.webhook.certTypeCrtKeyLabel', - { - defaultMessage: 'CRT and KEY file', - } -); -export const CERT_TYPE_PFX = i18n.translate( - 'xpack.stackConnectors.components.webhook.certTypePfxLabel', - { - defaultMessage: 'PFX file', - } -); - -export const CRT_REQUIRED = i18n.translate( - 'xpack.stackConnectors.components.webhook.error.requiredWebhookCRTText', - { - defaultMessage: 'CRT file is required.', - } -); - -export const KEY_REQUIRED = i18n.translate( - 'xpack.stackConnectors.components.webhook.error.requiredWebhookKEYText', - { - defaultMessage: 'KEY file is required.', - } -); - -export const PFX_REQUIRED = i18n.translate( - 'xpack.stackConnectors.components.webhook.error.requiredWebhookPFXText', - { - defaultMessage: 'PFX file is required.', - } -); - -export const CA_REQUIRED = i18n.translate( - 'xpack.stackConnectors.components.webhook.error.requiredWebhookCAText', - { - defaultMessage: 'CA file is required.', - } -); - -export const ADD_CA_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.viewCertificateAuthoritySwitch', - { - defaultMessage: 'Add certificate authority', - } -); - -export const VERIFICATION_MODE_LABEL = i18n.translate( - 'xpack.stackConnectors.components.webhook.verificationModeFieldLabel', - { defaultMessage: 'Verification mode' } -); - -export const EDIT_CA_CALLOUT = i18n.translate( - 'xpack.stackConnectors.components.webhook.editCACallout', - { - defaultMessage: - 'This webhook has an existing certificate authority file. Upload a new one to replace it.', - } -); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.test.tsx index 6b74624caaf9af..b9e2983964457a 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.test.tsx @@ -11,10 +11,10 @@ import WebhookActionConnectorFields from './webhook_connectors'; import { ConnectorFormTestProvider, waitForComponentToUpdate } from '../lib/test_utils'; import { act, render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { WebhookAuthType, SSLCertType } from '../../../common/webhook/constants'; +import { AuthType, SSLCertType } from '../../../common/auth/constants'; describe('WebhookActionConnectorFields renders', () => { - test('all connector fields is rendered', async () => { + it('renders all connector fields', async () => { const actionConnector = { actionTypeId: '.webhook', name: 'webhook', @@ -23,7 +23,7 @@ describe('WebhookActionConnectorFields renders', () => { url: 'https://test.com', headers: [{ key: 'content-type', value: 'text' }], hasAuth: true, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, }, secrets: { user: 'user', @@ -104,7 +104,7 @@ describe('WebhookActionConnectorFields renders', () => { url: 'https://test.com', headers: [{ key: 'content-type', value: 'text' }], hasAuth: true, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, }, secrets: { user: 'user', @@ -171,7 +171,7 @@ describe('WebhookActionConnectorFields renders', () => { method: 'PUT', url: 'https://test.com', hasAuth: true, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, }, }; @@ -197,7 +197,7 @@ describe('WebhookActionConnectorFields renders', () => { method: 'PUT', url: 'https://test.com', hasAuth: true, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, }, secrets: { user: 'user', @@ -303,7 +303,7 @@ describe('WebhookActionConnectorFields renders', () => { method: 'PUT', url: 'https://test.com', hasAuth: true, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, ca: Buffer.from('some binary string').toString('base64'), verificationMode: 'full', headers: [{ key: 'content-type', value: 'text' }], @@ -327,7 +327,7 @@ describe('WebhookActionConnectorFields renders', () => { ...actionConnector, config: { ...actionConnector.config, - authType: WebhookAuthType.SSL, + authType: AuthType.SSL, certType: SSLCertType.CRT, }, secrets: { @@ -358,7 +358,7 @@ describe('WebhookActionConnectorFields renders', () => { method: 'PUT', url: 'https://test.com', hasAuth: true, - authType: WebhookAuthType.SSL, + authType: AuthType.SSL, certType: SSLCertType.CRT, headers: [{ key: 'content-type', value: 'text' }], }, @@ -381,7 +381,7 @@ describe('WebhookActionConnectorFields renders', () => { ...actionConnector, config: { ...actionConnector.config, - authType: WebhookAuthType.SSL, + authType: AuthType.SSL, certType: SSLCertType.PFX, }, secrets: { @@ -411,7 +411,7 @@ describe('WebhookActionConnectorFields renders', () => { method: 'PUT', url: 'https://test.com', hasAuth: true, - authType: WebhookAuthType.SSL, + authType: AuthType.SSL, certType: SSLCertType.PFX, headers: [{ key: 'content-type', value: 'text' }], }, @@ -433,7 +433,7 @@ describe('WebhookActionConnectorFields renders', () => { ...actionConnector, config: { ...actionConnector.config, - authType: WebhookAuthType.SSL, + authType: AuthType.SSL, certType: SSLCertType.CRT, }, secrets: { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx b/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx index f99f0c964a5783..0c567127e4811b 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx @@ -5,237 +5,25 @@ * 2.0. */ -import React, { useEffect } from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiButtonIcon, - EuiTitle, - EuiButtonEmpty, - EuiCallOut, - EuiTabs, - EuiTab, -} from '@elastic/eui'; -import { - UseArray, - UseField, - useFormContext, - useFormData, -} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { - Field, - SelectField, - TextField, - ToggleField, - PasswordField, - FilePickerField, - CardRadioGroupField, - HiddenField, -} from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { Field, SelectField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; -import { WebhookAuthType, SSLCertType } from '../../../common/webhook/constants'; + import * as i18n from './translations'; +import { AuthConfig } from '../../common/auth/auth_config'; const HTTP_VERBS = ['post', 'put']; const { emptyField, urlField } = fieldValidators; -const VERIFICATION_MODE_DEFAULT = 'full'; const WebhookActionConnectorFields: React.FunctionComponent = ({ readOnly, }) => { - const { setFieldValue, getFieldDefaultValue } = useFormContext(); - const [{ config, __internal__ }] = useFormData({ - watch: [ - 'config.hasAuth', - 'config.authType', - 'config.certType', - 'config.verificationMode', - '__internal__.hasHeaders', - '__internal__.hasCA', - ], - }); - - const hasHeadersDefaultValue = !!getFieldDefaultValue('config.headers'); - const authTypeDefaultValue = - getFieldDefaultValue('config.hasAuth') === false - ? null - : getFieldDefaultValue('config.authType') ?? WebhookAuthType.Basic; - const certTypeDefaultValue = getFieldDefaultValue('config.certType') ?? SSLCertType.CRT; - const hasCADefaultValue = - !!getFieldDefaultValue('config.ca') || - getFieldDefaultValue('config.verificationMode') === 'none'; - - const hasHeaders = __internal__ != null ? __internal__.hasHeaders : false; - const hasCA = __internal__ != null ? __internal__.hasCA : false; - const authType = config == null ? WebhookAuthType.Basic : config.authType; - const certType = config == null ? SSLCertType.CRT : config.certType; - - const hasInitialCA = !!getFieldDefaultValue('config.ca'); - - useEffect(() => setFieldValue('config.hasAuth', Boolean(authType)), [authType, setFieldValue]); - - const basicAuthFields = ( - - - - - - - - - ); - - const sslCertAuthFields = ( - - - - - ( - - field.setValue(SSLCertType.CRT)} - isSelected={field.value === SSLCertType.CRT} - > - {i18n.CERT_TYPE_CRT_KEY} - - field.setValue(SSLCertType.PFX)} - isSelected={field.value === SSLCertType.PFX} - > - {i18n.CERT_TYPE_PFX} - - - )} - /> - - {certType === SSLCertType.CRT && ( - - - - - - - - - )} - {certType === SSLCertType.PFX && ( - - )} - - - ); - return ( <> - - - - - -

- -

-
- - -
-
- - - - {hasHeaders ? ( - <> - - - {({ items, addItem, removeItem }) => { - return ( - <> - {items.map((item) => ( - - - - - - - - - removeItem(item.id)} - iconType="minusInCircle" - aria-label={i18n.REMOVE_ITEM_LABEL} - style={{ marginTop: '28px' }} - /> - - - ))} - - - {i18n.ADD_HEADER_BTN} - - - - ); - }} - - - ) : null} - - - {hasCA && ( - <> - - - {}, - }, - ], - }} - component={FilePickerField} - componentProps={{ - euiFieldProps: { - display: 'default', - 'data-test-subj': 'webhookCAInput', - accept: '.ca,.pem', - }, - }} - /> - - - - - - {hasInitialCA && ( - <> - - - - )} - - )} + ); }; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts index 9bfb66f1a69aa8..62dd8816086057 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts @@ -26,12 +26,13 @@ import { ExternalIncidentServiceSecretConfigurationSchema, } from './schema'; import { api } from './api'; -import { validate } from './validators'; +import { validateCasesWebhookConfig, validateConnector } from './validators'; import * as i18n from './translations'; const supportedSubActions: string[] = ['pushToService']; export type ActionParamsType = CasesWebhookActionParamsType; export const ConnectorTypeId = '.cases-webhook'; + // connector type definition export function getConnectorType(): ConnectorType< CasesWebhookPublicConfigurationType, @@ -46,16 +47,15 @@ export function getConnectorType(): ConnectorType< validate: { config: { schema: ExternalIncidentServiceConfigurationSchema, - customValidator: validate.config, + customValidator: validateCasesWebhookConfig, }, secrets: { schema: ExternalIncidentServiceSecretConfigurationSchema, - customValidator: validate.secrets, }, params: { schema: ExecutorParamsSchema, }, - connector: validate.connector, + connector: validateConnector, }, executor, supportedFeatureIds: [CasesConnectorFeatureId], diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/schema.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/schema.ts index 9863b1457628a5..00b4fdc60a3ab9 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/schema.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/schema.ts @@ -6,17 +6,17 @@ */ import { schema } from '@kbn/config-schema'; -import { CasesWebhookMethods } from './types'; -import { nullableType } from '../lib/nullable'; +import { WebhookMethods } from '../../../common/auth/constants'; +import { AuthConfiguration, SecretConfigurationSchema } from '../../../common/auth/schema'; const HeadersSchema = schema.recordOf(schema.string(), schema.string()); export const ExternalIncidentServiceConfiguration = { createIncidentUrl: schema.string(), createIncidentMethod: schema.oneOf( - [schema.literal(CasesWebhookMethods.POST), schema.literal(CasesWebhookMethods.PUT)], + [schema.literal(WebhookMethods.POST), schema.literal(WebhookMethods.PUT)], { - defaultValue: CasesWebhookMethods.POST, + defaultValue: WebhookMethods.POST, } ), createIncidentJson: schema.string(), // stringified object @@ -27,12 +27,12 @@ export const ExternalIncidentServiceConfiguration = { updateIncidentUrl: schema.string(), updateIncidentMethod: schema.oneOf( [ - schema.literal(CasesWebhookMethods.POST), - schema.literal(CasesWebhookMethods.PATCH), - schema.literal(CasesWebhookMethods.PUT), + schema.literal(WebhookMethods.POST), + schema.literal(WebhookMethods.PATCH), + schema.literal(WebhookMethods.PUT), ], { - defaultValue: CasesWebhookMethods.PUT, + defaultValue: WebhookMethods.PUT, } ), updateIncidentJson: schema.string(), @@ -40,33 +40,28 @@ export const ExternalIncidentServiceConfiguration = { createCommentMethod: schema.nullable( schema.oneOf( [ - schema.literal(CasesWebhookMethods.POST), - schema.literal(CasesWebhookMethods.PUT), - schema.literal(CasesWebhookMethods.PATCH), + schema.literal(WebhookMethods.POST), + schema.literal(WebhookMethods.PUT), + schema.literal(WebhookMethods.PATCH), ], { - defaultValue: CasesWebhookMethods.PUT, + defaultValue: WebhookMethods.PUT, } ) ), createCommentJson: schema.nullable(schema.string()), - headers: nullableType(HeadersSchema), - hasAuth: schema.boolean({ defaultValue: true }), + headers: schema.nullable(HeadersSchema), + hasAuth: AuthConfiguration.hasAuth, + authType: AuthConfiguration.authType, + certType: AuthConfiguration.certType, + ca: AuthConfiguration.ca, + verificationMode: AuthConfiguration.verificationMode, }; export const ExternalIncidentServiceConfigurationSchema = schema.object( ExternalIncidentServiceConfiguration ); -export const ExternalIncidentServiceSecretConfiguration = { - user: schema.nullable(schema.string()), - password: schema.nullable(schema.string()), -}; - -export const ExternalIncidentServiceSecretConfigurationSchema = schema.object( - ExternalIncidentServiceSecretConfiguration -); - export const ExecutorSubActionPushParamsSchema = schema.object({ incident: schema.object({ title: schema.string(), @@ -93,3 +88,5 @@ export const ExecutorParamsSchema = schema.oneOf([ subActionParams: ExecutorSubActionPushParamsSchema, }), ]); + +export const ExternalIncidentServiceSecretConfigurationSchema = SecretConfigurationSchema; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index 1e7b492ada9594..3a8cf2895e60ec 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -9,11 +9,14 @@ import axios, { AxiosError, AxiosResponse } from 'axios'; import { createExternalService } from './service'; import { request, createAxiosResponse } from '@kbn/actions-plugin/server/lib/axios_utils'; -import { CasesWebhookMethods, CasesWebhookPublicConfigurationType, ExternalService } from './types'; +import { CasesWebhookPublicConfigurationType, ExternalService } from './types'; import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { AuthType, WebhookMethods, SSLCertType } from '../../../common/auth/constants'; +import { CRT_FILE, KEY_FILE } from '../../../common/auth/mocks'; + const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { @@ -25,36 +28,51 @@ jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { }); axios.create = jest.fn(() => axios); + const requestMock = request as jest.Mock; const configurationUtilities = actionsConfigMock.create(); const config: CasesWebhookPublicConfigurationType = { createCommentJson: '{"body":{{{case.comment}}}}', - createCommentMethod: CasesWebhookMethods.POST, + createCommentMethod: WebhookMethods.POST, createCommentUrl: 'https://coolsite.net/issue/{{{external.system.id}}}/comment', createIncidentJson: '{"fields":{"title":{{{case.title}}},"description":{{{case.description}}},"tags":{{{case.tags}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}', - createIncidentMethod: CasesWebhookMethods.POST, + createIncidentMethod: WebhookMethods.POST, createIncidentResponseKey: 'id', createIncidentUrl: 'https://coolsite.net/issue', getIncidentResponseExternalTitleKey: 'key', hasAuth: true, - headers: { ['content-type']: 'application/json' }, + headers: { ['content-type']: 'application/json', foo: 'bar' }, viewIncidentUrl: 'https://coolsite.net/browse/{{{external.system.title}}}', getIncidentUrl: 'https://coolsite.net/issue/{{{external.system.id}}}', updateIncidentJson: '{"fields":{"title":{{{case.title}}},"description":{{{case.description}}},"tags":{{{case.tags}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}', - updateIncidentMethod: CasesWebhookMethods.PUT, + updateIncidentMethod: WebhookMethods.PUT, updateIncidentUrl: 'https://coolsite.net/issue/{{{external.system.id}}}', }; const secrets = { user: 'user', password: 'pass', + crt: null, + key: null, + pfx: null, }; +const defaultSSLOverrides = {}; const actionId = '1234'; const mockTime = new Date('2021-10-20T19:41:02.754+0300'); + +const sslConfig: CasesWebhookPublicConfigurationType = { + ...config, + authType: AuthType.SSL, + certType: SSLCertType.CRT, + hasAuth: true, +}; +const sslSecrets = { crt: CRT_FILE, key: KEY_FILE, password: 'foobar', user: null, pfx: null }; + describe('Cases webhook service', () => { let service: ExternalService; + let sslService: ExternalService; beforeAll(() => { service = createExternalService( @@ -66,6 +84,16 @@ describe('Cases webhook service', () => { logger, configurationUtilities ); + + sslService = createExternalService( + actionId, + { + config: sslConfig, + secrets: sslSecrets, + }, + logger, + configurationUtilities + ); jest.useFakeTimers(); jest.setSystemTime(mockTime); }); @@ -98,13 +126,13 @@ describe('Cases webhook service', () => { ).toThrow(); }); - test('throws if hasAuth and no user/pass', () => { + it('throws if hasAuth and no user/pass', () => { expect(() => createExternalService( actionId, { config, - secrets: { user: '', password: '' }, + secrets: { ...secrets, user: '', password: '' }, }, logger, configurationUtilities @@ -112,13 +140,13 @@ describe('Cases webhook service', () => { ).toThrow(); }); - test('does not throw if hasAuth=false and no user/pass', () => { + it('does not throw if hasAuth=false and no user/pass', () => { expect(() => createExternalService( actionId, { config: { ...config, hasAuth: false }, - secrets: { user: '', password: '' }, + secrets: { ...secrets, user: '', password: '' }, }, logger, configurationUtilities @@ -126,12 +154,12 @@ describe('Cases webhook service', () => { ).not.toThrow(); }); - test('uses the basic auth header for authentication', () => { + it('uses the basic auth header for authentication', () => { createExternalService( actionId, { config, - secrets: { user: 'username', password: 'password' }, + secrets: { ...secrets, user: 'username', password: 'password' }, }, logger, configurationUtilities @@ -141,16 +169,17 @@ describe('Cases webhook service', () => { headers: { ...getBasicAuthHeader({ username: 'username', password: 'password' }), 'content-type': 'application/json', + foo: 'bar', }, }); }); - test('does not add the basic auth header for authentication if hasAuth=false', () => { + it('does not add the basic auth header for authentication if hasAuth=false', () => { createExternalService( actionId, { config: { ...config, hasAuth: false }, - secrets: { user: 'username', password: 'password' }, + secrets: { ...secrets, user: 'username', password: 'password' }, }, logger, configurationUtilities @@ -159,6 +188,7 @@ describe('Cases webhook service', () => { expect(axios.create).toHaveBeenCalledWith({ headers: { 'content-type': 'application/json', + foo: 'bar', }, }); }); @@ -176,7 +206,7 @@ describe('Cases webhook service', () => { }, }; - test('it returns the incident correctly', async () => { + it('it returns the incident correctly', async () => { requestMock.mockImplementation(() => createAxiosResponse(axiosRes)); const res = await service.getIncident('1'); expect(res).toEqual({ @@ -185,7 +215,7 @@ describe('Cases webhook service', () => { }); }); - test('it should call request with correct arguments', async () => { + it('it should call request with correct arguments', async () => { requestMock.mockImplementation(() => createAxiosResponse(axiosRes)); await service.getIncident('1'); @@ -194,10 +224,161 @@ describe('Cases webhook service', () => { url: 'https://coolsite.net/issue/1', logger, configurationUtilities, + sslOverrides: defaultSSLOverrides, }); }); - test('it should throw an error', async () => { + it('it should call request with correct arguments when authType=SSL', async () => { + requestMock.mockImplementation(() => createAxiosResponse(axiosRes)); + + await sslService.getIncident('1'); + + // irrelevant snapshot content + delete requestMock.mock.calls[0][0].configurationUtilities; + expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "axios": [Function], + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "sslOverrides": Object { + "cert": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "key": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "passphrase": "foobar", + }, + "url": "https://coolsite.net/issue/1", + } + `); + }); + + it('it should throw an error', async () => { requestMock.mockImplementation(() => { const error: AxiosError = new Error('An error has occurred') as AxiosError; error.response = { statusText: 'Required field' } as AxiosResponse; @@ -208,7 +389,7 @@ describe('Cases webhook service', () => { ); }); - test('it should throw if the request is not a JSON', async () => { + it('it should throw if the request is not a JSON', async () => { requestMock.mockImplementation(() => createAxiosResponse({ ...axiosRes, headers: { ['content-type']: 'text/html' } }) ); @@ -218,7 +399,7 @@ describe('Cases webhook service', () => { ); }); - test('it should throw if the required attributes are not there', async () => { + it('it should throw if the required attributes are not there', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { fields: { notRequired: 'test' } } }) ); @@ -241,7 +422,7 @@ describe('Cases webhook service', () => { }, }; - test('it creates the incident correctly', async () => { + it('it creates the incident correctly', async () => { requestMock.mockImplementationOnce(() => createAxiosResponse({ data: { id: '1', key: 'CK-1', fields: { title: 'title', description: 'description' } }, @@ -271,7 +452,7 @@ describe('Cases webhook service', () => { }); }); - test('it should call request with correct arguments', async () => { + it('it should call request with correct arguments', async () => { requestMock.mockImplementationOnce(() => createAxiosResponse({ data: { @@ -296,13 +477,194 @@ describe('Cases webhook service', () => { axios, url: 'https://coolsite.net/issue', logger, - method: CasesWebhookMethods.POST, + method: WebhookMethods.POST, configurationUtilities, + sslOverrides: defaultSSLOverrides, data: `{"fields":{"title":"title","description":"desc","tags":["hello","world"],"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}`, }); }); - test('it should throw an error', async () => { + it('it should call request with correct arguments when authType=SSL', async () => { + requestMock.mockImplementationOnce(() => + createAxiosResponse({ + data: { + id: '1', + key: 'CK-1', + }, + }) + ); + + requestMock.mockImplementationOnce(() => + createAxiosResponse({ + data: { + id: '1', + key: 'CK-1', + }, + }) + ); + + await sslService.createIncident(incident); + + // irrelevant snapshot content + delete requestMock.mock.calls[0][0].configurationUtilities; + expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "axios": [Function], + "data": "{\\"fields\\":{\\"title\\":\\"title\\",\\"description\\":\\"desc\\",\\"tags\\":[\\"hello\\",\\"world\\"],\\"project\\":{\\"key\\":\\"ROC\\"},\\"issuetype\\":{\\"id\\":\\"10024\\"}}}", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"1234\\": [HTTP 200] OK", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "method": "post", + "sslOverrides": Object { + "cert": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "key": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "passphrase": "foobar", + }, + "url": "https://coolsite.net/issue", + } + `); + }); + + it('it should throw an error', async () => { requestMock.mockImplementation(() => { const error: AxiosError = new Error('An error has occurred') as AxiosError; error.response = { statusText: 'Required field' } as AxiosResponse; @@ -314,7 +676,7 @@ describe('Cases webhook service', () => { ); }); - test('it should throw if the request is not a JSON', async () => { + it('it should throw if the request is not a JSON', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { id: '1' }, headers: { ['content-type']: 'text/html' } }) ); @@ -324,7 +686,7 @@ describe('Cases webhook service', () => { ); }); - test('it should throw if the required attributes are not there', async () => { + it('it should throw if the required attributes are not there', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); await expect(service.createIncident(incident)).rejects.toThrow( @@ -346,7 +708,7 @@ describe('Cases webhook service', () => { }, }; - test('it updates the incident correctly', async () => { + it('it updates the incident correctly', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { @@ -366,7 +728,7 @@ describe('Cases webhook service', () => { }); }); - test('it should call request with correct arguments', async () => { + it('it should call request with correct arguments', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { @@ -381,8 +743,9 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toEqual({ axios, logger, - method: CasesWebhookMethods.PUT, + method: WebhookMethods.PUT, configurationUtilities, + sslOverrides: defaultSSLOverrides, url: 'https://coolsite.net/issue/1', data: JSON.stringify({ fields: { @@ -396,7 +759,166 @@ describe('Cases webhook service', () => { }); }); - test('it should throw an error', async () => { + it('it should call request with correct arguments when authType=SSL', async () => { + requestMock.mockImplementation(() => + createAxiosResponse({ + data: { + id: '1', + key: 'CK-1', + }, + }) + ); + + await sslService.updateIncident(incident); + + // irrelevant snapshot content + delete requestMock.mock.calls[0][0].configurationUtilities; + expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "axios": [Function], + "data": "{\\"fields\\":{\\"title\\":\\"title\\",\\"description\\":\\"desc\\",\\"tags\\":[\\"hello\\",\\"world\\"],\\"project\\":{\\"key\\":\\"ROC\\"},\\"issuetype\\":{\\"id\\":\\"10024\\"}}}", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "method": "put", + "sslOverrides": Object { + "cert": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "key": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "passphrase": "foobar", + }, + "url": "https://coolsite.net/issue/1", + } + `); + }); + + it('it should throw an error', async () => { requestMock.mockImplementation(() => { const error: AxiosError = new Error('An error has occurred') as AxiosError; error.response = { statusText: 'Required field' } as AxiosResponse; @@ -408,7 +930,7 @@ describe('Cases webhook service', () => { ); }); - test('it should throw if the request is not a JSON', async () => { + it('it should throw if the request is not a JSON', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { id: '1' }, headers: { ['content-type']: 'text/html' } }) ); @@ -427,7 +949,7 @@ describe('Cases webhook service', () => { commentId: 'comment-1', }, }; - test('it creates the comment correctly', async () => { + it('it creates the comment correctly', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { @@ -442,7 +964,7 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0].data).toEqual('{"body":"comment"}'); }); - test('it should call request with correct arguments', async () => { + it('it should call request with correct arguments', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { @@ -457,14 +979,174 @@ describe('Cases webhook service', () => { expect(requestMock).toHaveBeenCalledWith({ axios, logger, - method: CasesWebhookMethods.POST, + method: WebhookMethods.POST, configurationUtilities, + sslOverrides: defaultSSLOverrides, url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment"}`, }); }); - test('it should throw an error', async () => { + it('it should call request with correct arguments when authType=SSL', async () => { + requestMock.mockImplementation(() => + createAxiosResponse({ + data: { + id: '1', + key: 'CK-1', + }, + }) + ); + + await sslService.createComment(commentReq); + + // irrelevant snapshot content + delete requestMock.mock.calls[0][0].configurationUtilities; + expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "axios": [Function], + "data": "{\\"body\\":\\"comment\\"}", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "method": "post", + "sslOverrides": Object { + "cert": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "key": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "passphrase": "foobar", + }, + "url": "https://coolsite.net/issue/1/comment", + } + `); + }); + + it('it should throw an error', async () => { requestMock.mockImplementation(() => { const error: AxiosError = new Error('An error has occurred') as AxiosError; error.response = { statusText: 'Required field' } as AxiosResponse; @@ -476,7 +1158,7 @@ describe('Cases webhook service', () => { ); }); - test('it should throw if the request is not a JSON', async () => { + it('it should throw if the request is not a JSON', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { id: '1' }, headers: { ['content-type']: 'text/html' } }) ); @@ -486,7 +1168,7 @@ describe('Cases webhook service', () => { ); }); - test('it fails silently if createCommentUrl is missing', async () => { + it('it fails silently if createCommentUrl is missing', async () => { service = createExternalService( actionId, { @@ -501,7 +1183,7 @@ describe('Cases webhook service', () => { expect(res).toBeUndefined(); }); - test('it fails silently if createCommentJson is missing', async () => { + it('it fails silently if createCommentJson is missing', async () => { service = createExternalService( actionId, { @@ -516,7 +1198,7 @@ describe('Cases webhook service', () => { expect(res).toBeUndefined(); }); - test('properly encodes external system id as string in request body', async () => { + it('properly encodes external system id as string in request body', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { @@ -541,14 +1223,15 @@ describe('Cases webhook service', () => { expect(requestMock).toHaveBeenCalledWith({ axios, logger, - method: CasesWebhookMethods.POST, + method: WebhookMethods.POST, configurationUtilities, url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":"1"}`, + sslOverrides: defaultSSLOverrides, }); }); - test('properly encodes external system id as number in request body', async () => { + it('properly encodes external system id as number in request body', async () => { const commentReq2 = { incidentId: 1 as unknown as string, comment: { @@ -580,10 +1263,11 @@ describe('Cases webhook service', () => { expect(requestMock).toHaveBeenCalledWith({ axios, logger, - method: CasesWebhookMethods.POST, + method: WebhookMethods.POST, configurationUtilities, url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":1}`, + sslOverrides: defaultSSLOverrides, }); }); }); @@ -609,12 +1293,12 @@ describe('Cases webhook service', () => { beforeEach(() => { jest.clearAllMocks(); }); - test('getIncident- throws for bad url', async () => { + it('getIncident- throws for bad url', async () => { await expect(service.getIncident('whack')).rejects.toThrow( '[Action][Webhook - Case Management]: Unable to get case with id whack. Error: Invalid Get case URL: Error: error configuring connector action: Uri not allowed.' ); }); - test('createIncident- throws for bad url', async () => { + it('createIncident- throws for bad url', async () => { const incident = { incident: { title: 'title', @@ -630,7 +1314,7 @@ describe('Cases webhook service', () => { '[Action][Webhook - Case Management]: Unable to create case. Error: Invalid Create case URL: Error: error configuring connector action: Uri not allowed.' ); }); - test('updateIncident- throws for bad url', async () => { + it('updateIncident- throws for bad url', async () => { const incident = { incidentId: '123', incident: { @@ -647,7 +1331,7 @@ describe('Cases webhook service', () => { '[Action][Webhook - Case Management]: Unable to update case with id 123. Error: Invalid Update case URL: Error: error configuring connector action: Uri not allowed.' ); }); - test('createComment- throws for bad url', async () => { + it('createComment- throws for bad url', async () => { const commentReq = { incidentId: '1', comment: { @@ -683,12 +1367,12 @@ describe('Cases webhook service', () => { beforeEach(() => { jest.clearAllMocks(); }); - test('getIncident- throws for bad protocol', async () => { + it('getIncident- throws for bad protocol', async () => { await expect(service.getIncident('whack')).rejects.toThrow( '[Action][Webhook - Case Management]: Unable to get case with id whack. Error: Invalid Get case URL: Error: Invalid protocol.' ); }); - test('createIncident- throws for bad protocol', async () => { + it('createIncident- throws for bad protocol', async () => { const incident = { incident: { title: 'title', @@ -704,7 +1388,7 @@ describe('Cases webhook service', () => { '[Action][Webhook - Case Management]: Unable to create case. Error: Invalid Create case URL: Error: Invalid protocol.' ); }); - test('updateIncident- throws for bad protocol', async () => { + it('updateIncident- throws for bad protocol', async () => { const incident = { incidentId: '123', incident: { @@ -721,7 +1405,7 @@ describe('Cases webhook service', () => { '[Action][Webhook - Case Management]: Unable to update case with id 123. Error: Invalid Update case URL: Error: Invalid protocol.' ); }); - test('createComment- throws for bad protocol', async () => { + it('createComment- throws for bad protocol', async () => { const commentReq = { incidentId: '1', comment: { @@ -761,14 +1445,14 @@ describe('Cases webhook service', () => { beforeEach(() => { jest.clearAllMocks(); }); - test('getIncident- escapes url', async () => { + it('getIncident- escapes url', async () => { await service.getIncident('../../malicious-app/malicious-endpoint/'); expect(requestMock.mock.calls[0][0].url).toEqual( 'https://coolsite.net/issue/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F' ); }); - test('createIncident- escapes url', async () => { + it('createIncident- escapes url', async () => { const incident = { incident: { title: 'title', @@ -785,7 +1469,7 @@ describe('Cases webhook service', () => { ); }); - test('updateIncident- escapes url', async () => { + it('updateIncident- escapes url', async () => { const incident = { incidentId: '../../malicious-app/malicious-endpoint/', incident: { @@ -803,7 +1487,7 @@ describe('Cases webhook service', () => { 'https://coolsite.net/issue/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F' ); }); - test('createComment- escapes url', async () => { + it('createComment- escapes url', async () => { const commentReq = { incidentId: '../../malicious-app/malicious-endpoint/', comment: { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts index 46407c18bd0816..424fe9b394517a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts @@ -12,6 +12,7 @@ import { renderMustacheStringNoEscape } from '@kbn/actions-plugin/server/lib/mus import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { buildConnectorAuth, validateConnectorAuthConfiguration } from '../../../common/auth/utils'; import { validateAndNormalizeUrl, validateJson } from './validators'; import { createServiceError, @@ -20,12 +21,11 @@ import { removeSlash, throwDescriptiveErrorIfResponseIsNotValid, } from './utils'; -import { +import type { CreateIncidentParams, ExternalServiceCredentials, ExternalService, CasesWebhookPublicConfigurationType, - CasesWebhookSecretConfigurationType, ExternalServiceIncidentResponse, GetIncidentResponse, UpdateIncidentParams, @@ -51,31 +51,41 @@ export const createExternalService = ( getIncidentResponseExternalTitleKey, getIncidentUrl, hasAuth, + authType, headers, viewIncidentUrl, updateIncidentJson, updateIncidentMethod, updateIncidentUrl, + verificationMode, + ca, } = config as CasesWebhookPublicConfigurationType; - const { password, user } = secrets as CasesWebhookSecretConfigurationType; - if ( - !getIncidentUrl || - !createIncidentUrlConfig || - !viewIncidentUrl || - !updateIncidentUrl || - (hasAuth && (!password || !user)) - ) { + + const { basicAuth, sslOverrides } = buildConnectorAuth({ + hasAuth, + authType, + secrets, + verificationMode, + ca, + }); + + validateConnectorAuthConfiguration({ + hasAuth, + authType, + basicAuth, + sslOverrides, + connectorName: i18n.NAME, + }); + + if (!getIncidentUrl || !createIncidentUrlConfig || !viewIncidentUrl || !updateIncidentUrl) { throw Error(`[Action]${i18n.NAME}: Wrong configuration.`); } - const createIncidentUrl = removeSlash(createIncidentUrlConfig); - const headersWithBasicAuth = hasAuth - ? combineHeadersWithBasicAuthHeader({ - username: user ?? undefined, - password: password ?? undefined, - headers, - }) - : {}; + const headersWithBasicAuth = combineHeadersWithBasicAuthHeader({ + username: basicAuth.auth?.username, + password: basicAuth.auth?.password, + headers, + }); const axiosInstance = axios.create({ headers: { @@ -84,6 +94,8 @@ export const createExternalService = ( }, }); + const createIncidentUrl = removeSlash(createIncidentUrlConfig); + const getIncident = async (id: string): Promise => { try { const getUrl = renderMustacheStringNoEscape(getIncidentUrl, { @@ -104,6 +116,7 @@ export const createExternalService = ( url: normalizedUrl, logger, configurationUtilities, + sslOverrides, }); throwDescriptiveErrorIfResponseIsNotValid({ @@ -148,6 +161,7 @@ export const createExternalService = ( method: createIncidentMethod, data: json, configurationUtilities, + sslOverrides, }); const { status, statusText, data } = res; @@ -231,6 +245,7 @@ export const createExternalService = ( logger, data: json, configurationUtilities, + sslOverrides, }); throwDescriptiveErrorIfResponseIsNotValid({ @@ -303,6 +318,7 @@ export const createExternalService = ( logger, data: json, configurationUtilities, + sslOverrides, }); throwDescriptiveErrorIfResponseIsNotValid({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/translations.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/translations.ts index a3180e6cca6636..188c4516d22a30 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/translations.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/translations.ts @@ -28,12 +28,9 @@ export const CONFIG_ERR = (err: string) => }, }); -export const INVALID_USER_PW = i18n.translate( - 'xpack.stackConnectors.casesWebhook.invalidUsernamePassword', - { - defaultMessage: 'both user and password must be specified', - } -); +export const INVALID_AUTH = i18n.translate('xpack.stackConnectors.casesWebhook.invalidSecrets', { + defaultMessage: 'must specify a secrets configuration', +}); export const ALLOWED_HOSTS_ERROR = (message: string) => i18n.translate('xpack.stackConnectors.casesWebhook.configuration.apiAllowedHostsError', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts index c4404748fc33bb..95af6d5e306f26 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/types.ts @@ -7,7 +7,6 @@ import { TypeOf } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; -import { ValidatorServices } from '@kbn/actions-plugin/server/types'; import { ExecutorParamsSchema, ExecutorSubActionPushParamsSchema, @@ -15,13 +14,6 @@ import { ExternalIncidentServiceSecretConfigurationSchema, } from './schema'; -// config definition -export enum CasesWebhookMethods { - PATCH = 'patch', - POST = 'post', - PUT = 'put', -} - // config export type CasesWebhookPublicConfigurationType = TypeOf< typeof ExternalIncidentServiceConfigurationSchema @@ -38,21 +30,6 @@ export interface ExternalServiceCredentials { secrets: CasesWebhookSecretConfigurationType; } -export interface ExternalServiceValidation { - config: ( - configObject: CasesWebhookPublicConfigurationType, - validatorServices: ValidatorServices - ) => void; - secrets: ( - secrets: CasesWebhookSecretConfigurationType, - validatorServices: ValidatorServices - ) => void; - connector: ( - configObject: CasesWebhookPublicConfigurationType, - secrets: CasesWebhookSecretConfigurationType - ) => string | null; -} - export interface ExternalServiceIncidentResponse { id: string; title: string; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/validators.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/validators.ts index 95265cfcaf6ef9..21922d608156ea 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/validators.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/validators.ts @@ -7,14 +7,11 @@ import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { ValidatorServices } from '@kbn/actions-plugin/server/types'; +import { isEmpty } from 'lodash'; import * as i18n from './translations'; -import { - CasesWebhookPublicConfigurationType, - CasesWebhookSecretConfigurationType, - ExternalServiceValidation, -} from './types'; +import { CasesWebhookPublicConfigurationType, CasesWebhookSecretConfigurationType } from './types'; -const validateConfig = ( +export const validateCasesWebhookConfig = ( configObject: CasesWebhookPublicConfigurationType, validatorServices: ValidatorServices ) => { @@ -55,26 +52,8 @@ export const validateConnector = ( configObject: CasesWebhookPublicConfigurationType, secrets: CasesWebhookSecretConfigurationType ): string | null => { - // user and password must be set together (or not at all) - if (!configObject.hasAuth) return null; - if (secrets.password && secrets.user) return null; - return i18n.INVALID_USER_PW; -}; - -export const validateSecrets = ( - secrets: CasesWebhookSecretConfigurationType, - validatorServices: ValidatorServices -) => { - // user and password must be set together (or not at all) - if (!secrets.password && !secrets.user) return; - if (secrets.password && secrets.user) return; - throw new Error(i18n.INVALID_USER_PW); -}; - -export const validate: ExternalServiceValidation = { - config: validateConfig, - secrets: validateSecrets, - connector: validateConnector, + if (configObject.hasAuth && isEmpty(secrets)) return i18n.INVALID_AUTH; + return null; }; const validProtocols: string[] = ['http:', 'https:']; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/index.ts index 04c7004f7325b0..6364fed0e193ff 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/index.ts @@ -58,7 +58,7 @@ export type { SlackApiActionParams as SlackApiActionParams } from '../../common/ export { ConnectorTypeId as TeamsConnectorTypeId } from './teams'; export type { ActionParamsType as TeamsActionParams } from './teams'; export { ConnectorTypeId as WebhookConnectorTypeId } from './webhook'; -export type { ActionParamsType as WebhookActionParams } from './webhook'; +export type { ActionParamsType as WebhookActionParams } from './webhook/types'; export { ConnectorTypeId as XmattersConnectorTypeId } from './xmatters'; export type { ActionParamsType as XmattersActionParams } from './xmatters'; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/nullable.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/nullable.ts deleted file mode 100644 index af95e728465da8..00000000000000 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/nullable.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema, Type } from '@kbn/config-schema'; - -// TODO: remove once this is merged: https://github.com/elastic/kibana/pull/41728 - -export function nullableType(type: Type) { - return schema.oneOf([type, schema.literal(null)], { defaultValue: () => null }); -} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts index 9e82b2d2c31e7e..6c51fe11e97de3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts @@ -12,18 +12,14 @@ import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/action import { Logger } from '@kbn/core/server'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import axios from 'axios'; -import { - ConnectorTypeConfigType, - ConnectorTypeSecretsType, - getConnectorType, - WebhookConnectorType, - WebhookMethods, -} from '.'; +import { ConnectorTypeConfigType, ConnectorTypeSecretsType, WebhookConnectorType } from './types'; + +import { getConnectorType } from '.'; import * as utils from '@kbn/actions-plugin/server/lib/axios_utils'; import { loggerMock } from '@kbn/logging-mocks'; -import { SSLCertType, WebhookAuthType } from '../../../common/webhook/constants'; -import { PFX_FILE, CRT_FILE, KEY_FILE } from './mocks'; +import { AuthType, SSLCertType, WebhookMethods } from '../../../common/auth/constants'; +import { PFX_FILE, CRT_FILE, KEY_FILE } from '../../../common/auth/mocks'; jest.mock('axios'); jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { @@ -157,7 +153,7 @@ describe('config validation', () => { test('config validation passes when only required fields are provided', () => { const config: Record = { url: 'http://mylisteningserver:9200/endpoint', - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, hasAuth: true, }; expect(validateConfig(connectorType, config, { configurationUtilities })).toEqual({ @@ -171,7 +167,7 @@ describe('config validation', () => { const config: Record = { url: 'http://mylisteningserver:9200/endpoint', method, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, hasAuth: true, }; expect(validateConfig(connectorType, config, { configurationUtilities })).toEqual({ @@ -198,7 +194,7 @@ describe('config validation', () => { test('config validation passes when a url is specified', () => { const config: Record = { url: 'http://mylisteningserver:9200/endpoint', - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, hasAuth: true, }; expect(validateConfig(connectorType, config, { configurationUtilities })).toEqual({ @@ -226,7 +222,7 @@ describe('config validation', () => { headers: { 'Content-Type': 'application/json', }, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, hasAuth: true, }; expect(validateConfig(connectorType, config, { configurationUtilities })).toEqual({ @@ -257,7 +253,7 @@ describe('config validation', () => { headers: { 'Content-Type': 'application/json', }, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, hasAuth: true, }; @@ -332,7 +328,7 @@ describe('execute()', () => { headers: { aheader: 'a value', }, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, hasAuth: true, }; await connectorType.executor({ @@ -392,7 +388,7 @@ describe('execute()', () => { headers: { aheader: 'a value', }, - authType: WebhookAuthType.SSL, + authType: AuthType.SSL, certType: SSLCertType.CRT, hasAuth: true, }; @@ -575,7 +571,7 @@ describe('execute()', () => { headers: { aheader: 'a value', }, - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, hasAuth: true, }; requestMock.mockReset(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts index c5314f8e5f7adc..78f02d24b9b87c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts @@ -6,18 +6,16 @@ */ import { i18n } from '@kbn/i18n'; -import { isString } from 'lodash'; import axios, { AxiosError, AxiosResponse } from 'axios'; -import { schema, TypeOf } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, getOrElse } from 'fp-ts/lib/Option'; + import type { - ActionType as ConnectorType, - ActionTypeExecutorOptions as ConnectorTypeExecutorOptions, ActionTypeExecutorResult as ConnectorTypeExecutorResult, ValidatorServices, } from '@kbn/actions-plugin/server/types'; + import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { AlertingConnectorFeatureId, @@ -26,90 +24,23 @@ import { } from '@kbn/actions-plugin/common/types'; import { renderMustacheString } from '@kbn/actions-plugin/server/lib/mustache_renderer'; import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; -import { SSLCertType, WebhookAuthType } from '../../../common/webhook/constants'; -import { getRetryAfterIntervalFromHeaders } from '../lib/http_response_retry_header'; -import { nullableType } from '../lib/nullable'; -import { isOk, promiseResult, Result } from '../lib/result_type'; - -// config definition -export enum WebhookMethods { - POST = 'post', - PUT = 'put', -} -export type WebhookConnectorType = ConnectorType< - ConnectorTypeConfigType, - ConnectorTypeSecretsType, +import type { + WebhookConnectorType, ActionParamsType, - unknown ->; -export type WebhookConnectorTypeExecutorOptions = ConnectorTypeExecutorOptions< ConnectorTypeConfigType, + WebhookConnectorTypeExecutorOptions, ConnectorTypeSecretsType, - ActionParamsType ->; +} from './types'; -const HeadersSchema = schema.recordOf(schema.string(), schema.string()); -const configSchemaProps = { - url: schema.string(), - method: schema.oneOf([schema.literal(WebhookMethods.POST), schema.literal(WebhookMethods.PUT)], { - defaultValue: WebhookMethods.POST, - }), - headers: nullableType(HeadersSchema), - hasAuth: schema.boolean({ defaultValue: true }), - authType: schema.maybe( - schema.oneOf( - [ - schema.literal(WebhookAuthType.Basic), - schema.literal(WebhookAuthType.SSL), - schema.literal(null), - ], - { - defaultValue: WebhookAuthType.Basic, - } - ) - ), - certType: schema.maybe( - schema.oneOf([schema.literal(SSLCertType.CRT), schema.literal(SSLCertType.PFX)]) - ), - ca: schema.maybe(schema.string()), - verificationMode: schema.maybe( - schema.oneOf([schema.literal('none'), schema.literal('certificate'), schema.literal('full')]) - ), -}; -const ConfigSchema = schema.object(configSchemaProps); -export type ConnectorTypeConfigType = TypeOf; - -// secrets definition -export type ConnectorTypeSecretsType = TypeOf; -const secretSchemaProps = { - user: schema.nullable(schema.string()), - password: schema.nullable(schema.string()), - crt: schema.nullable(schema.string()), - key: schema.nullable(schema.string()), - pfx: schema.nullable(schema.string()), -}; -const SecretsSchema = schema.object(secretSchemaProps, { - validate: (secrets) => { - // user and password must be set together (or not at all) - if (!secrets.password && !secrets.user && !secrets.crt && !secrets.key && !secrets.pfx) return; - if (secrets.password && secrets.user && !secrets.crt && !secrets.key && !secrets.pfx) return; - if (secrets.crt && secrets.key && !secrets.user && !secrets.pfx) return; - if (!secrets.crt && !secrets.key && !secrets.user && secrets.pfx) return; - return i18n.translate('xpack.stackConnectors.webhook.invalidUsernamePassword', { - defaultMessage: - 'must specify one of the following schemas: user and password; crt and key (with optional password); or pfx (with optional password)', - }); - }, -}); - -// params definition -export type ActionParamsType = TypeOf; -export const ParamsSchema = schema.object({ - body: schema.maybe(schema.string()), -}); +import { getRetryAfterIntervalFromHeaders } from '../lib/http_response_retry_header'; +import { isOk, promiseResult, Result } from '../lib/result_type'; +import { ConfigSchema, ParamsSchema } from './schema'; +import { buildConnectorAuth } from '../../../common/auth/utils'; +import { SecretConfigurationSchema } from '../../../common/auth/schema'; export const ConnectorTypeId = '.webhook'; + // connector type definition export function getConnectorType(): WebhookConnectorType { return { @@ -129,7 +60,7 @@ export function getConnectorType(): WebhookConnectorType { customValidator: validateConnectorTypeConfig, }, secrets: { - schema: SecretsSchema, + schema: SecretConfigurationSchema, }, params: { schema: ParamsSchema, @@ -202,39 +133,16 @@ export async function executor( const { body: data } = params; const secrets: ConnectorTypeSecretsType = execOptions.secrets; - // For backwards compatibility with connectors created before authType was added, interpret a - // hasAuth: true and undefined authType as basic auth - const basicAuth = - hasAuth && - (authType === WebhookAuthType.Basic || !authType) && - isString(secrets.user) && - isString(secrets.password) - ? { auth: { username: secrets.user, password: secrets.password } } - : {}; - - const sslCertificate = - authType === WebhookAuthType.SSL && - ((isString(secrets.crt) && isString(secrets.key)) || isString(secrets.pfx)) - ? isString(secrets.pfx) - ? { - pfx: Buffer.from(secrets.pfx, 'base64'), - ...(isString(secrets.password) ? { passphrase: secrets.password } : {}), - } - : { - cert: Buffer.from(secrets.crt!, 'base64'), - key: Buffer.from(secrets.key!, 'base64'), - ...(isString(secrets.password) ? { passphrase: secrets.password } : {}), - } - : {}; + const { basicAuth, sslOverrides } = buildConnectorAuth({ + hasAuth, + authType, + secrets, + verificationMode, + ca, + }); const axiosInstance = axios.create(); - const sslOverrides = { - ...sslCertificate, - ...(verificationMode ? { verificationMode } : {}), - ...(ca ? { ca: Buffer.from(ca, 'base64') } : {}), - }; - const headersWithBasicAuth = combineHeadersWithBasicAuthHeader({ username: basicAuth.auth?.username, password: basicAuth.auth?.password, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/schema.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/schema.ts new file mode 100644 index 00000000000000..b6eca5de787f33 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/schema.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { AuthConfiguration } from '../../../common/auth/schema'; +import { WebhookMethods } from '../../../common/auth/constants'; + +export const HeadersSchema = schema.recordOf(schema.string(), schema.string()); + +const configSchemaProps = { + url: schema.string(), + method: schema.oneOf([schema.literal(WebhookMethods.POST), schema.literal(WebhookMethods.PUT)], { + defaultValue: WebhookMethods.POST, + }), + headers: schema.nullable(HeadersSchema), + hasAuth: AuthConfiguration.hasAuth, + authType: AuthConfiguration.authType, + certType: AuthConfiguration.certType, + ca: AuthConfiguration.ca, + verificationMode: AuthConfiguration.verificationMode, +}; + +export const ConfigSchema = schema.object(configSchemaProps); + +// params definition +export const ParamsSchema = schema.object({ + body: schema.maybe(schema.string()), +}); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/types.ts new file mode 100644 index 00000000000000..4857a88f2a0421 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/types.ts @@ -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 { TypeOf } from '@kbn/config-schema'; +import type { + ActionType as ConnectorType, + ActionTypeExecutorOptions as ConnectorTypeExecutorOptions, +} from '@kbn/actions-plugin/server/types'; +import { ParamsSchema, ConfigSchema } from './schema'; +import { SecretConfigurationSchema } from '../../../common/auth/schema'; + +export type WebhookConnectorType = ConnectorType< + ConnectorTypeConfigType, + ConnectorTypeSecretsType, + ActionParamsType, + unknown +>; +export type WebhookConnectorTypeExecutorOptions = ConnectorTypeExecutorOptions< + ConnectorTypeConfigType, + ConnectorTypeSecretsType, + ActionParamsType +>; + +export type ConnectorTypeConfigType = TypeOf; + +// secrets definition +export type ConnectorTypeSecretsType = TypeOf; + +// params definition +export type ActionParamsType = TypeOf; diff --git a/x-pack/plugins/stack_connectors/server/index.ts b/x-pack/plugins/stack_connectors/server/index.ts index 0069036c4ea838..38fc3b3297c58a 100644 --- a/x-pack/plugins/stack_connectors/server/index.ts +++ b/x-pack/plugins/stack_connectors/server/index.ts @@ -10,7 +10,7 @@ import { SlackApiParamsSchema } from '../common/slack_api/schema'; export { ParamsSchema as SlackParamsSchema } from './connector_types/slack'; export { ParamsSchema as EmailParamsSchema } from './connector_types/email'; -export { ParamsSchema as WebhookParamsSchema } from './connector_types/webhook'; +export { ParamsSchema as WebhookParamsSchema } from './connector_types/webhook/schema'; export { ExecutorParamsSchema as JiraParamsSchema } from './connector_types/jira/schema'; export { ParamsSchema as PagerdutyParamsSchema } from './connector_types/pagerduty'; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index eec216c68d5842..fd47cd081f8780 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -39312,7 +39312,6 @@ "xpack.stackConnectors.xmatters.invalidUrlError": "secretsUrl non valide : {err}", "xpack.stackConnectors.xmatters.postingRetryErrorMessage": "Erreur lors du déclenchement du flux xMatters : statut http {status}, réessayer plus tard", "xpack.stackConnectors.xmatters.unexpectedStatusErrorMessage": "Erreur de déclenchement du flux xMatters : statut inattendu {status}", - "xpack.stackConnectors.casesWebhook.invalidUsernamePassword": "l'utilisateur et le mot de passe doivent être spécifiés", "xpack.stackConnectors.casesWebhook.title": "Webhook - Gestion des cas", "xpack.stackConnectors.components.bedrock.accessKeySecret": "Clé d'accès", "xpack.stackConnectors.components.bedrock.apiUrlTextFieldLabel": "URL", @@ -39327,9 +39326,7 @@ "xpack.stackConnectors.components.bedrock.selectMessageText": "Envoyer une requête à Amazon Bedrock.", "xpack.stackConnectors.components.bedrock.title": "Amazon Bedrock", "xpack.stackConnectors.components.bedrock.urlTextFieldLabel": "URL", - "xpack.stackConnectors.components.casesWebhook.addHeaderButton": "Ajouter", "xpack.stackConnectors.components.casesWebhook.addVariable": "Ajouter une variable", - "xpack.stackConnectors.components.casesWebhook.authenticationLabel": "Authentification", "xpack.stackConnectors.components.casesWebhook.caseCommentDesc": "Commentaire de cas Kibana", "xpack.stackConnectors.components.casesWebhook.caseDescriptionDesc": "Description de cas Kibana", "xpack.stackConnectors.components.casesWebhook.caseIdDesc": "ID de cas Kibana", @@ -39352,11 +39349,8 @@ "xpack.stackConnectors.components.casesWebhook.createIncidentResponseKeyTextFieldLabel": "Clé externe dans la réponse de création d'un cas", "xpack.stackConnectors.components.casesWebhook.createIncidentUrlTextFieldLabel": "URL de création d'un cas", "xpack.stackConnectors.components.casesWebhook.criticalLabel": "Critique", - "xpack.stackConnectors.components.casesWebhook.deleteHeaderButton": "Supprimer", "xpack.stackConnectors.components.casesWebhook.descriptionTextAreaFieldLabel": "Description", "xpack.stackConnectors.components.casesWebhook.docLink": "Configuration de Webhook - Connecteur de gestion des cas.", - "xpack.stackConnectors.components.casesWebhook.error.requiredAuthPasswordText": "Le mot de passe est requis.", - "xpack.stackConnectors.components.casesWebhook.error.requiredAuthUserNameText": "Le nom d'utilisateur est requis.", "xpack.stackConnectors.components.casesWebhook.error.requiredCreateCommentIncidentText": "L'objet de création de commentaire doit être un JSON valide.", "xpack.stackConnectors.components.casesWebhook.error.requiredCreateCommentMethodText": "La méthode de création de commentaire est requise.", "xpack.stackConnectors.components.casesWebhook.error.requiredCreateCommentUrlText": "L'URL de création de commentaire doit être au format URL.", @@ -39381,15 +39375,12 @@ "xpack.stackConnectors.components.casesWebhook.getIncidentUrlTextFieldLabel": "URL d'obtention de cas", "xpack.stackConnectors.components.casesWebhook.hasAuthSwitchLabel": "Demander une authentification pour ce webhook", "xpack.stackConnectors.components.casesWebhook.highLabel": "Élevé", - "xpack.stackConnectors.components.casesWebhook.httpHeadersTitle": "En-têtes utilisés", "xpack.stackConnectors.components.casesWebhook.idFieldLabel": "ID de cas", "xpack.stackConnectors.components.casesWebhook.jsonCodeEditorAriaLabel": "Éditeur de code", "xpack.stackConnectors.components.casesWebhook.jsonFieldLabel": "JSON", - "xpack.stackConnectors.components.casesWebhook.keyTextFieldLabel": "Clé", "xpack.stackConnectors.components.casesWebhook.lowLabel": "Bas", "xpack.stackConnectors.components.casesWebhook.mediumLabel": "Moyenne", "xpack.stackConnectors.components.casesWebhook.next": "Suivant", - "xpack.stackConnectors.components.casesWebhook.passwordTextFieldLabel": "Mot de passe", "xpack.stackConnectors.components.casesWebhook.previous": "Précédent", "xpack.stackConnectors.components.casesWebhook.selectMessageText": "Envoyer une requête à un service web de gestion de cas.", "xpack.stackConnectors.components.casesWebhook.severityFieldLabel": "Sévérité", @@ -39414,9 +39405,6 @@ "xpack.stackConnectors.components.casesWebhook.updateIncidentMethodTextFieldLabel": "Méthode de mise à jour de cas", "xpack.stackConnectors.components.casesWebhook.updateIncidentUrlHelp": "URL d'API pour mettre à jour un cas.", "xpack.stackConnectors.components.casesWebhook.updateIncidentUrlTextFieldLabel": "URL de mise à jour du cas", - "xpack.stackConnectors.components.casesWebhook.userTextFieldLabel": "Nom d'utilisateur", - "xpack.stackConnectors.components.casesWebhook.valueTextFieldLabel": "Valeur", - "xpack.stackConnectors.components.casesWebhook.viewHeadersSwitch": "Ajouter un en-tête HTTP", "xpack.stackConnectors.components.casesWebhook.viewIncidentUrlHelp": "URL pour afficher un cas dans le système externe. Utilisez le sélecteur de variable pour ajouter à l'URL l'ID ou le titre du système externe.", "xpack.stackConnectors.components.casesWebhook.viewIncidentUrlTextFieldLabel": "URL de visualisation de cas externe", "xpack.stackConnectors.components.casesWebhookxpack.stackConnectors.components.casesWebhook.connectorTypeTitle": "Webhook - Données de gestion des cas", @@ -39766,39 +39754,15 @@ "xpack.stackConnectors.components.teams.messageTextAreaFieldLabel": "Message", "xpack.stackConnectors.components.teams.selectMessageText": "Envoyer un message à un canal Microsoft Teams.", "xpack.stackConnectors.components.teams.webhookUrlHelpLabel": "Créer une URL de webhook Microsoft Teams", - "xpack.stackConnectors.components.webhook.addHeaderButtonLabel": "Ajouter un en-tête", - "xpack.stackConnectors.components.webhook.authenticationLabel": "Authentification", - "xpack.stackConnectors.components.webhook.authenticationMethodBasicLabel": "Authentification de base", - "xpack.stackConnectors.components.webhook.authenticationMethodNoneLabel": "Aucun", - "xpack.stackConnectors.components.webhook.authenticationMethodSSLLabel": "Authentification SSL", "xpack.stackConnectors.components.webhook.bodyCodeEditorAriaLabel": "Éditeur de code", "xpack.stackConnectors.components.webhook.bodyFieldLabel": "Corps", - "xpack.stackConnectors.components.webhook.certTypeCrtKeyLabel": "Fichier CRT et KEY", - "xpack.stackConnectors.components.webhook.certTypePfxLabel": "Fichier PFX", "xpack.stackConnectors.components.webhook.connectorTypeTitle": "Données de webhook", - "xpack.stackConnectors.components.webhook.editCACallout": "Ce webhook comporte déjà un fichier d'autorité de certificat. Charger un nouveau pour le remplacer.", "xpack.stackConnectors.components.webhook.error.invalidUrlTextField": "L'URL n'est pas valide.", - "xpack.stackConnectors.components.webhook.error.requiredAuthUserNameText": "Le nom d'utilisateur est requis.", "xpack.stackConnectors.components.webhook.error.requiredMethodText": "La méthode est requise.", "xpack.stackConnectors.components.webhook.error.requiredWebhookBodyText": "Le corps est requis.", - "xpack.stackConnectors.components.webhook.error.requiredWebhookCAText": "Le fichier CA est requis.", - "xpack.stackConnectors.components.webhook.error.requiredWebhookCRTText": "Le fichier CRT est requis.", - "xpack.stackConnectors.components.webhook.error.requiredWebhookKEYText": "Le fichier KEY est requis.", - "xpack.stackConnectors.components.webhook.error.requiredWebhookPasswordText": "Le mot de passe est requis.", - "xpack.stackConnectors.components.webhook.error.requiredWebhookPFXText": "Le fichier PFX est requis.", - "xpack.stackConnectors.components.webhook.hasAuthSwitchLabel": "Demander une authentification pour ce webhook", - "xpack.stackConnectors.components.webhook.headerKeyTextFieldLabel": "Clé", - "xpack.stackConnectors.components.webhook.headerValueTextFieldLabel": "Valeur", "xpack.stackConnectors.components.webhook.methodTextFieldLabel": "Méthode", - "xpack.stackConnectors.components.webhook.passphraseTextFieldLabel": "Phrase secrète", - "xpack.stackConnectors.components.webhook.passwordTextFieldLabel": "Mot de passe", - "xpack.stackConnectors.components.webhook.removeHeaderIconLabel": "Clé", "xpack.stackConnectors.components.webhook.selectMessageText": "Envoyer une requête à un service Web.", "xpack.stackConnectors.components.webhook.urlTextFieldLabel": "URL", - "xpack.stackConnectors.components.webhook.userTextFieldLabel": "Nom d'utilisateur", - "xpack.stackConnectors.components.webhook.verificationModeFieldLabel": "Mode de vérification", - "xpack.stackConnectors.components.webhook.viewCertificateAuthoritySwitch": "Ajouter une autorité de certificat", - "xpack.stackConnectors.components.webhook.viewHeadersSwitch": "Ajouter un en-tête HTTP", "xpack.stackConnectors.components.xmatters.authenticationLabel": "Authentification", "xpack.stackConnectors.components.xmatters.basicAuthButtonGroupLegend": "Authentification de base", "xpack.stackConnectors.components.xmatters.basicAuthLabel": "Authentification de base", @@ -39975,7 +39939,6 @@ "xpack.stackConnectors.webhook.authConfigurationError": "erreur lors de la configuration d'action webhook : authType doit être null ou undefined si hasAuth est faux", "xpack.stackConnectors.webhook.invalidResponseErrorMessage": "erreur lors de l'appel de webhook, réponse non valide", "xpack.stackConnectors.webhook.invalidResponseRetryLaterErrorMessage": "erreur lors de l'appel de webhook, réessayer ultérieurement", - "xpack.stackConnectors.webhook.invalidUsernamePassword": "doit préciser l'un des schémas suivants : utilisateur et mot de passe, crt et key (avec mot de passe facultatif) ou pfx (avec mot de passe facultatif)", "xpack.stackConnectors.webhook.requestFailedErrorMessage": "erreur lors de l'appel de webhook, requête échouée", "xpack.stackConnectors.webhook.title": "Webhook", "xpack.stackConnectors.webhook.unexpectedNullResponseErrorMessage": "réponse nulle inattendue de webhook", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e59e2a03790431..7e2f411d770c2a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -39284,7 +39284,6 @@ "xpack.stackConnectors.xmatters.invalidUrlError": "無効なsecretsUrl:{err}", "xpack.stackConnectors.xmatters.postingRetryErrorMessage": "xMattersフローのトリガーエラー:HTTPステータス{status}。しばらくたってから再試行してください", "xpack.stackConnectors.xmatters.unexpectedStatusErrorMessage": "xMattersフローのトリガーエラー:予期しないステータス{status}", - "xpack.stackConnectors.casesWebhook.invalidUsernamePassword": "ユーザーとパスワードの両方を指定する必要があります", "xpack.stackConnectors.casesWebhook.title": "Webフック - ケース管理", "xpack.stackConnectors.components.bedrock.accessKeySecret": "アクセスキー", "xpack.stackConnectors.components.bedrock.apiUrlTextFieldLabel": "URL", @@ -39299,9 +39298,7 @@ "xpack.stackConnectors.components.bedrock.selectMessageText": "Amazon Bedrockにリクエストを送信します。", "xpack.stackConnectors.components.bedrock.title": "Amazon Bedrock", "xpack.stackConnectors.components.bedrock.urlTextFieldLabel": "URL", - "xpack.stackConnectors.components.casesWebhook.addHeaderButton": "追加", "xpack.stackConnectors.components.casesWebhook.addVariable": "変数を追加", - "xpack.stackConnectors.components.casesWebhook.authenticationLabel": "認証", "xpack.stackConnectors.components.casesWebhook.caseCommentDesc": "Kibanaケースコメント", "xpack.stackConnectors.components.casesWebhook.caseDescriptionDesc": "Kibanaケース説明", "xpack.stackConnectors.components.casesWebhook.caseIdDesc": "KibanaケースID", @@ -39324,11 +39321,8 @@ "xpack.stackConnectors.components.casesWebhook.createIncidentResponseKeyTextFieldLabel": "ケース対応の作成の外部キー", "xpack.stackConnectors.components.casesWebhook.createIncidentUrlTextFieldLabel": "ケースURLを作成", "xpack.stackConnectors.components.casesWebhook.criticalLabel": "重大", - "xpack.stackConnectors.components.casesWebhook.deleteHeaderButton": "削除", "xpack.stackConnectors.components.casesWebhook.descriptionTextAreaFieldLabel": "説明", "xpack.stackConnectors.components.casesWebhook.docLink": "Webフックの構成 - ケース管理コネクター。", - "xpack.stackConnectors.components.casesWebhook.error.requiredAuthPasswordText": "パスワードが必要です。", - "xpack.stackConnectors.components.casesWebhook.error.requiredAuthUserNameText": "ユーザー名が必要です。", "xpack.stackConnectors.components.casesWebhook.error.requiredCreateCommentIncidentText": "コメントオブジェクトの作成は有効なJSONでなければなりません。", "xpack.stackConnectors.components.casesWebhook.error.requiredCreateCommentMethodText": "コメントメソッドを作成は必須です。", "xpack.stackConnectors.components.casesWebhook.error.requiredCreateCommentUrlText": "コメントURLの作成はURL形式でなければなりません。", @@ -39353,15 +39347,12 @@ "xpack.stackConnectors.components.casesWebhook.getIncidentUrlTextFieldLabel": "ケースURLを取得", "xpack.stackConnectors.components.casesWebhook.hasAuthSwitchLabel": "この Web フックの認証が必要です", "xpack.stackConnectors.components.casesWebhook.highLabel": "高", - "xpack.stackConnectors.components.casesWebhook.httpHeadersTitle": "使用中のヘッダー", "xpack.stackConnectors.components.casesWebhook.idFieldLabel": "ケースID", "xpack.stackConnectors.components.casesWebhook.jsonCodeEditorAriaLabel": "コードエディター", "xpack.stackConnectors.components.casesWebhook.jsonFieldLabel": "JSON", - "xpack.stackConnectors.components.casesWebhook.keyTextFieldLabel": "キー", "xpack.stackConnectors.components.casesWebhook.lowLabel": "低", "xpack.stackConnectors.components.casesWebhook.mediumLabel": "中", "xpack.stackConnectors.components.casesWebhook.next": "次へ", - "xpack.stackConnectors.components.casesWebhook.passwordTextFieldLabel": "パスワード", "xpack.stackConnectors.components.casesWebhook.previous": "前へ", "xpack.stackConnectors.components.casesWebhook.selectMessageText": "ケース管理Webサービスにリクエストを送信します。", "xpack.stackConnectors.components.casesWebhook.severityFieldLabel": "深刻度", @@ -39386,9 +39377,6 @@ "xpack.stackConnectors.components.casesWebhook.updateIncidentMethodTextFieldLabel": "ケースメソッドを更新", "xpack.stackConnectors.components.casesWebhook.updateIncidentUrlHelp": "ケースを更新するAPI URL。", "xpack.stackConnectors.components.casesWebhook.updateIncidentUrlTextFieldLabel": "ケースURLを更新", - "xpack.stackConnectors.components.casesWebhook.userTextFieldLabel": "ユーザー名", - "xpack.stackConnectors.components.casesWebhook.valueTextFieldLabel": "値", - "xpack.stackConnectors.components.casesWebhook.viewHeadersSwitch": "HTTP ヘッダーを追加", "xpack.stackConnectors.components.casesWebhook.viewIncidentUrlHelp": "外部システムでケースを表示するURL。変数セレクターを使用して、外部システムIDまたは外部システムタイトルをURLに追加します。", "xpack.stackConnectors.components.casesWebhook.viewIncidentUrlTextFieldLabel": "外部ケース表示URL", "xpack.stackConnectors.components.casesWebhookxpack.stackConnectors.components.casesWebhook.connectorTypeTitle": "Webフック - ケース管理データ", @@ -39738,39 +39726,15 @@ "xpack.stackConnectors.components.teams.messageTextAreaFieldLabel": "メッセージ", "xpack.stackConnectors.components.teams.selectMessageText": "メッセージを Microsoft Teams チャネルに送信します。", "xpack.stackConnectors.components.teams.webhookUrlHelpLabel": "Microsoft Teams Web フック URL を作成", - "xpack.stackConnectors.components.webhook.addHeaderButtonLabel": "ヘッダーを追加", - "xpack.stackConnectors.components.webhook.authenticationLabel": "認証", - "xpack.stackConnectors.components.webhook.authenticationMethodBasicLabel": "基本認証", - "xpack.stackConnectors.components.webhook.authenticationMethodNoneLabel": "なし", - "xpack.stackConnectors.components.webhook.authenticationMethodSSLLabel": "SSL認証", "xpack.stackConnectors.components.webhook.bodyCodeEditorAriaLabel": "コードエディター", "xpack.stackConnectors.components.webhook.bodyFieldLabel": "本文", - "xpack.stackConnectors.components.webhook.certTypeCrtKeyLabel": "CRTおよびKEYファイル", - "xpack.stackConnectors.components.webhook.certTypePfxLabel": "PFXファイル", "xpack.stackConnectors.components.webhook.connectorTypeTitle": "Web フックデータ", - "xpack.stackConnectors.components.webhook.editCACallout": "このWebフックには既存の認証局ファイルがあります。新しいファイルをアップロードして置き換えてください。", "xpack.stackConnectors.components.webhook.error.invalidUrlTextField": "URL が無効です。", - "xpack.stackConnectors.components.webhook.error.requiredAuthUserNameText": "ユーザー名が必要です。", "xpack.stackConnectors.components.webhook.error.requiredMethodText": "メソッドが必要です。", "xpack.stackConnectors.components.webhook.error.requiredWebhookBodyText": "本文が必要です。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookCAText": "CAファイルが必要です。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookCRTText": "CRTファイルが必要です。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookKEYText": "KEYファイルが必要です。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookPasswordText": "パスワードが必要です。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookPFXText": "PFXファイルが必要です。", - "xpack.stackConnectors.components.webhook.hasAuthSwitchLabel": "この Web フックの認証が必要です", - "xpack.stackConnectors.components.webhook.headerKeyTextFieldLabel": "キー", - "xpack.stackConnectors.components.webhook.headerValueTextFieldLabel": "値", "xpack.stackConnectors.components.webhook.methodTextFieldLabel": "メソド", - "xpack.stackConnectors.components.webhook.passphraseTextFieldLabel": "パスフレーズ", - "xpack.stackConnectors.components.webhook.passwordTextFieldLabel": "パスワード", - "xpack.stackConnectors.components.webhook.removeHeaderIconLabel": "キー", "xpack.stackConnectors.components.webhook.selectMessageText": "Web サービスにリクエストを送信してください。", "xpack.stackConnectors.components.webhook.urlTextFieldLabel": "URL", - "xpack.stackConnectors.components.webhook.userTextFieldLabel": "ユーザー名", - "xpack.stackConnectors.components.webhook.verificationModeFieldLabel": "認証モード", - "xpack.stackConnectors.components.webhook.viewCertificateAuthoritySwitch": "認証局を追加", - "xpack.stackConnectors.components.webhook.viewHeadersSwitch": "HTTP ヘッダーを追加", "xpack.stackConnectors.components.xmatters.authenticationLabel": "認証", "xpack.stackConnectors.components.xmatters.basicAuthButtonGroupLegend": "基本認証", "xpack.stackConnectors.components.xmatters.basicAuthLabel": "基本認証", @@ -39947,7 +39911,6 @@ "xpack.stackConnectors.webhook.authConfigurationError": "webフックアクションの構成エラー:hasAuthがfalseの場合、authTypeはnullまたはundefinedでなければなりません", "xpack.stackConnectors.webhook.invalidResponseErrorMessage": "Webフックの呼び出しエラー、無効な応答", "xpack.stackConnectors.webhook.invalidResponseRetryLaterErrorMessage": "Webフックの呼び出しエラー、後ほど再試行", - "xpack.stackConnectors.webhook.invalidUsernamePassword": "ユーザーとパスワード、crtと鍵(任意のパスワード付き)、またはpfx(任意のパスワード付き)のいずれかのスキーマを指定する必要があります", "xpack.stackConnectors.webhook.requestFailedErrorMessage": "Webフックの呼び出しエラー。要求が失敗しました", "xpack.stackConnectors.webhook.title": "Web フック", "xpack.stackConnectors.webhook.unexpectedNullResponseErrorMessage": "Webフックからの予期しないnull応答", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 80a079b82c7018..d43efdcf980fb1 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -39330,7 +39330,6 @@ "xpack.stackConnectors.xmatters.invalidUrlError": "secretsUrl 无效:{err}", "xpack.stackConnectors.xmatters.postingRetryErrorMessage": "触发 xMatters 流时出错:http 状态为 {status},请稍后重试", "xpack.stackConnectors.xmatters.unexpectedStatusErrorMessage": "触发 xMatters 流时出错:非预期状态 {status}", - "xpack.stackConnectors.casesWebhook.invalidUsernamePassword": "必须指定用户及密码", "xpack.stackConnectors.casesWebhook.title": "Webhook - 案例管理", "xpack.stackConnectors.components.bedrock.accessKeySecret": "访问密钥", "xpack.stackConnectors.components.bedrock.apiUrlTextFieldLabel": "URL", @@ -39345,9 +39344,7 @@ "xpack.stackConnectors.components.bedrock.selectMessageText": "向 Amazon Bedrock 发送请求。", "xpack.stackConnectors.components.bedrock.title": "Amazon Bedrock", "xpack.stackConnectors.components.bedrock.urlTextFieldLabel": "URL", - "xpack.stackConnectors.components.casesWebhook.addHeaderButton": "添加", "xpack.stackConnectors.components.casesWebhook.addVariable": "添加变量", - "xpack.stackConnectors.components.casesWebhook.authenticationLabel": "身份验证", "xpack.stackConnectors.components.casesWebhook.caseCommentDesc": "Kibana 案例注释", "xpack.stackConnectors.components.casesWebhook.caseDescriptionDesc": "Kibana 案例描述", "xpack.stackConnectors.components.casesWebhook.caseIdDesc": "Kibana 案例 ID", @@ -39370,11 +39367,8 @@ "xpack.stackConnectors.components.casesWebhook.createIncidentResponseKeyTextFieldLabel": "创建案例响应外部键", "xpack.stackConnectors.components.casesWebhook.createIncidentUrlTextFieldLabel": "创建案例 URL", "xpack.stackConnectors.components.casesWebhook.criticalLabel": "紧急", - "xpack.stackConnectors.components.casesWebhook.deleteHeaderButton": "删除", "xpack.stackConnectors.components.casesWebhook.descriptionTextAreaFieldLabel": "描述", "xpack.stackConnectors.components.casesWebhook.docLink": "正在配置 Webhook - 案例管理连接器。", - "xpack.stackConnectors.components.casesWebhook.error.requiredAuthPasswordText": "“密码”必填。", - "xpack.stackConnectors.components.casesWebhook.error.requiredAuthUserNameText": "“用户名”必填。", "xpack.stackConnectors.components.casesWebhook.error.requiredCreateCommentIncidentText": "创建注释对象必须为有效 JSON。", "xpack.stackConnectors.components.casesWebhook.error.requiredCreateCommentMethodText": "“创建注释方法”必填。", "xpack.stackConnectors.components.casesWebhook.error.requiredCreateCommentUrlText": "创建注释 URL 必须为 URL 格式。", @@ -39399,15 +39393,12 @@ "xpack.stackConnectors.components.casesWebhook.getIncidentUrlTextFieldLabel": "获取案例 URL", "xpack.stackConnectors.components.casesWebhook.hasAuthSwitchLabel": "此 Webhook 需要身份验证", "xpack.stackConnectors.components.casesWebhook.highLabel": "高", - "xpack.stackConnectors.components.casesWebhook.httpHeadersTitle": "在用的标头", "xpack.stackConnectors.components.casesWebhook.idFieldLabel": "案例 ID", "xpack.stackConnectors.components.casesWebhook.jsonCodeEditorAriaLabel": "代码编辑器", "xpack.stackConnectors.components.casesWebhook.jsonFieldLabel": "JSON", - "xpack.stackConnectors.components.casesWebhook.keyTextFieldLabel": "钥匙", "xpack.stackConnectors.components.casesWebhook.lowLabel": "低", "xpack.stackConnectors.components.casesWebhook.mediumLabel": "中", "xpack.stackConnectors.components.casesWebhook.next": "下一步", - "xpack.stackConnectors.components.casesWebhook.passwordTextFieldLabel": "密码", "xpack.stackConnectors.components.casesWebhook.previous": "上一步", "xpack.stackConnectors.components.casesWebhook.selectMessageText": "发送请求到案例管理 Web 服务。", "xpack.stackConnectors.components.casesWebhook.severityFieldLabel": "严重性", @@ -39432,9 +39423,6 @@ "xpack.stackConnectors.components.casesWebhook.updateIncidentMethodTextFieldLabel": "更新案例方法", "xpack.stackConnectors.components.casesWebhook.updateIncidentUrlHelp": "用于更新案例的 API URL。", "xpack.stackConnectors.components.casesWebhook.updateIncidentUrlTextFieldLabel": "更新案例 URL", - "xpack.stackConnectors.components.casesWebhook.userTextFieldLabel": "用户名", - "xpack.stackConnectors.components.casesWebhook.valueTextFieldLabel": "值", - "xpack.stackConnectors.components.casesWebhook.viewHeadersSwitch": "添加 HTTP 标头", "xpack.stackConnectors.components.casesWebhook.viewIncidentUrlHelp": "用于查看外部系统中的案例的 URL。使用变量选择器添加外部系统 ID 或外部系统标题到 URL。", "xpack.stackConnectors.components.casesWebhook.viewIncidentUrlTextFieldLabel": "外部案例查看 URL", "xpack.stackConnectors.components.casesWebhookxpack.stackConnectors.components.casesWebhook.connectorTypeTitle": "Webhook - 案例管理数据", @@ -39784,39 +39772,15 @@ "xpack.stackConnectors.components.teams.messageTextAreaFieldLabel": "消息", "xpack.stackConnectors.components.teams.selectMessageText": "向 Microsoft Teams 频道发送消息。", "xpack.stackConnectors.components.teams.webhookUrlHelpLabel": "创建 Microsoft Teams Webhook URL", - "xpack.stackConnectors.components.webhook.addHeaderButtonLabel": "添加标头", - "xpack.stackConnectors.components.webhook.authenticationLabel": "身份验证", - "xpack.stackConnectors.components.webhook.authenticationMethodBasicLabel": "基本身份验证", - "xpack.stackConnectors.components.webhook.authenticationMethodNoneLabel": "无", - "xpack.stackConnectors.components.webhook.authenticationMethodSSLLabel": "SSL 身份验证", "xpack.stackConnectors.components.webhook.bodyCodeEditorAriaLabel": "代码编辑器", "xpack.stackConnectors.components.webhook.bodyFieldLabel": "正文", - "xpack.stackConnectors.components.webhook.certTypeCrtKeyLabel": "CRT 和 KEY 文件", - "xpack.stackConnectors.components.webhook.certTypePfxLabel": "PFX 文件", "xpack.stackConnectors.components.webhook.connectorTypeTitle": "Webhook 数据", - "xpack.stackConnectors.components.webhook.editCACallout": "此 Webhook 具有现有证书颁发机构文件。上传新文件将其替换。", "xpack.stackConnectors.components.webhook.error.invalidUrlTextField": "URL 无效。", - "xpack.stackConnectors.components.webhook.error.requiredAuthUserNameText": "“用户名”必填。", "xpack.stackConnectors.components.webhook.error.requiredMethodText": "“方法”必填", "xpack.stackConnectors.components.webhook.error.requiredWebhookBodyText": "“正文”必填。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookCAText": "CA 文件必填。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookCRTText": "CRT 文件必填。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookKEYText": "KEY 文件必填。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookPasswordText": "“密码”必填。", - "xpack.stackConnectors.components.webhook.error.requiredWebhookPFXText": "PFX 文件必填。", - "xpack.stackConnectors.components.webhook.hasAuthSwitchLabel": "此 Webhook 需要身份验证", - "xpack.stackConnectors.components.webhook.headerKeyTextFieldLabel": "钥匙", - "xpack.stackConnectors.components.webhook.headerValueTextFieldLabel": "值", "xpack.stackConnectors.components.webhook.methodTextFieldLabel": "方法", - "xpack.stackConnectors.components.webhook.passphraseTextFieldLabel": "密码", - "xpack.stackConnectors.components.webhook.passwordTextFieldLabel": "密码", - "xpack.stackConnectors.components.webhook.removeHeaderIconLabel": "钥匙", "xpack.stackConnectors.components.webhook.selectMessageText": "将请求发送到 Web 服务。", "xpack.stackConnectors.components.webhook.urlTextFieldLabel": "URL", - "xpack.stackConnectors.components.webhook.userTextFieldLabel": "用户名", - "xpack.stackConnectors.components.webhook.verificationModeFieldLabel": "验证模式", - "xpack.stackConnectors.components.webhook.viewCertificateAuthoritySwitch": "添加证书颁发机构", - "xpack.stackConnectors.components.webhook.viewHeadersSwitch": "添加 HTTP 标头", "xpack.stackConnectors.components.xmatters.authenticationLabel": "身份验证", "xpack.stackConnectors.components.xmatters.basicAuthButtonGroupLegend": "基本身份验证", "xpack.stackConnectors.components.xmatters.basicAuthLabel": "基本身份验证", @@ -39993,7 +39957,6 @@ "xpack.stackConnectors.webhook.authConfigurationError": "配置 Webhook 操作时出错:如果 hasAuth 为 false,authType 必须为 null 或未定义", "xpack.stackConnectors.webhook.invalidResponseErrorMessage": "调用 webhook 时出错,响应无效", "xpack.stackConnectors.webhook.invalidResponseRetryLaterErrorMessage": "调用 webhook 时出错,请稍后重试", - "xpack.stackConnectors.webhook.invalidUsernamePassword": "必须指定以下方案之一:用户和密码;crt 和密钥(密码可选);或 pfx(密码可选)", "xpack.stackConnectors.webhook.requestFailedErrorMessage": "调用 webhook 时出错,请求失败", "xpack.stackConnectors.webhook.title": "Webhook", "xpack.stackConnectors.webhook.unexpectedNullResponseErrorMessage": "来自 Webhook 的异常空响应", diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts index 35401f0c426a2d..f26ba86f6fa3ab 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts @@ -202,7 +202,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'error validating action type connector: both user and password must be specified', + 'error validating action type connector: must specify a secrets configuration', }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action.ts index 22ac52dc2a333c..091707df88d0a9 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/rule_bulk_actions/trial_license_complete_tier/perform_bulk_action.ts @@ -18,7 +18,7 @@ import { import { getCreateExceptionListDetectionSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_schema.mock'; import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getCreateExceptionListItemMinimalSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_exception_list_item_schema.mock'; -import { WebhookAuthType } from '@kbn/stack-connectors-plugin/common/webhook/constants'; +import { AuthType } from '@kbn/stack-connectors-plugin/common/auth/constants'; import { BaseDefaultableFields } from '@kbn/security-solution-plugin/common/api/detection_engine'; import { binaryToString, @@ -190,7 +190,7 @@ export default ({ getService }: FtrProviderContext): void => { attributes: { actionTypeId: '.webhook', config: { - authType: WebhookAuthType.Basic, + authType: AuthType.Basic, hasAuth: true, method: 'post', url: 'http://localhost', From 4a95ffbd9398a715504f55d54c0d6a8a19d52f7e Mon Sep 17 00:00:00 2001 From: Mark Hopkin Date: Tue, 18 Jun 2024 11:03:21 +0100 Subject: [PATCH 019/123] [Entity Analytics] Create public versions of asset criticality get,upsert,delete and csv upload APIs (#186169) ## Summary Adds 4 new public APIs for managing asset criticality. These are public versions of our existing internal asset criticality APIs: - Get record `GET /api/asset_criticality?id_field=x?id_value=y` - Upsert record`POST /api/asset_criticality` - Delete record `DELETE /api/asset_criticality?id_field=x?id_value=y` - Bulk CSV Upload `POST /api/asset_criticality/upload_csv` We will delete the internal versions in the future but for now we keep both. I have switched the tests and UI to use the public APIs. I have also moved our API versions to constants. ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../create_asset_criticality.schema.yaml | 20 ++ .../delete_asset_criticality.schema.yaml | 13 ++ .../get_asset_criticality.schema.yaml | 19 ++ .../upload_asset_criticality_csv.schema.yaml | 26 +++ .../asset_criticality/constants.ts | 15 +- .../common/entity_analytics/constants.ts | 9 + .../public/entity_analytics/api/api.ts | 40 ++-- .../asset_criticality/routes/delete.ts | 122 ++++++---- .../asset_criticality/routes/get.ts | 122 ++++++---- .../asset_criticality/routes/privileges.ts | 9 +- .../register_asset_criticality_routes.ts | 34 ++- .../asset_criticality/routes/status.ts | 72 +++--- .../asset_criticality/routes/upload_csv.ts | 221 +++++++++++------- .../asset_criticality/routes/upsert.ts | 134 +++++++---- .../utils/asset_criticality.ts | 33 +-- 15 files changed, 585 insertions(+), 304 deletions(-) diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml index 64f321c5a56cb6..4b5e52b5eb2112 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml @@ -15,6 +15,26 @@ paths: x-labels: [ess, serverless] x-internal: true operationId: AssetCriticalityCreateRecord + summary: Deprecated Internal Create Criticality Record + requestBody: + required: true + content: + application/json: + schema: + $ref: './common.schema.yaml#/components/schemas/CreateAssetCriticalityRecord' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './common.schema.yaml#/components/schemas/AssetCriticalityRecord' + '400': + description: Invalid request + /api/asset_criticality: + post: + x-labels: [ess, serverless] + operationId: AssetCriticalityCreateRecord summary: Create Criticality Record requestBody: required: true diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml index be882228c0bb01..94e1cc82e15ad4 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/delete_asset_criticality.schema.yaml @@ -15,6 +15,19 @@ paths: x-labels: [ess, serverless] x-internal: true operationId: AssetCriticalityDeleteRecord + summary: Deprecated Internal Delete Criticality Record + parameters: + - $ref: './common.schema.yaml#/components/parameters/id_value' + - $ref: './common.schema.yaml#/components/parameters/id_field' + responses: + '200': + description: Successful response + '400': + description: Invalid request + /api/asset_criticality: + delete: + x-labels: [ess, serverless] + operationId: AssetCriticalityDeleteRecord summary: Delete Criticality Record parameters: - $ref: './common.schema.yaml#/components/parameters/id_value' diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml index 664d8dbace2bf2..56f3e37de11264 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/get_asset_criticality.schema.yaml @@ -15,6 +15,25 @@ paths: x-labels: [ess, serverless] x-internal: true operationId: AssetCriticalityGetRecord + summary: Deprecated Internal Get Criticality Record + parameters: + - $ref: './common.schema.yaml#/components/parameters/id_value' + - $ref: './common.schema.yaml#/components/parameters/id_field' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: './common.schema.yaml#/components/schemas/AssetCriticalityRecord' + '400': + description: Invalid request + '404': + description: Criticality record not found + /api/asset_criticality: + get: + x-labels: [ess, serverless] + operationId: AssetCriticalityGetRecord summary: Get Criticality Record parameters: - $ref: './common.schema.yaml#/components/parameters/id_value' diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.schema.yaml index 440955f8954c2c..933839cea43a34 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.schema.yaml @@ -11,6 +11,32 @@ servers: default: '5601' paths: /internal/asset_criticality/upload_csv: + post: + x-labels: [ess, serverless] + x-internal: true + summary: Deprecated internal API which Uploads a CSV file containing asset criticality data + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + description: The CSV file to upload. + required: + - file + responses: + '200': + description: CSV upload successful + content: + application/json: + schema: + $ref: '#/components/schemas/AssetCriticalityCsvUploadResponse' + '413': + description: File too large + /api/asset_criticality/upload_csv: post: x-labels: [ess, serverless] x-internal: true diff --git a/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts b/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts index 73d9cccabc940f..d7d9854834d098 100644 --- a/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts +++ b/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts @@ -5,10 +5,17 @@ * 2.0. */ -export const ASSET_CRITICALITY_URL = `/internal/asset_criticality` as const; -export const ASSET_CRITICALITY_PRIVILEGES_URL = `${ASSET_CRITICALITY_URL}/privileges` as const; -export const ASSET_CRITICALITY_STATUS_URL = `${ASSET_CRITICALITY_URL}/status` as const; -export const ASSET_CRITICALITY_CSV_UPLOAD_URL = `${ASSET_CRITICALITY_URL}/upload_csv` as const; +export const ASSET_CRITICALITY_INTERNAL_URL = `/internal/asset_criticality` as const; +export const ASSET_CRITICALITY_INTERNAL_PRIVILEGES_URL = + `${ASSET_CRITICALITY_INTERNAL_URL}/privileges` as const; +export const ASSET_CRITICALITY_INTERNAL_STATUS_URL = + `${ASSET_CRITICALITY_INTERNAL_URL}/status` as const; +export const ASSET_CRITICALITY_INTERNAL_CSV_UPLOAD_URL = + `${ASSET_CRITICALITY_INTERNAL_URL}/upload_csv` as const; + +export const ASSET_CRITICALITY_PUBLIC_URL = `/api/asset_criticality` as const; +export const ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL = + `${ASSET_CRITICALITY_PUBLIC_URL}/upload_csv` as const; export const ASSET_CRITICALITY_INDEX_PATTERN = '.asset-criticality.asset-criticality-*'; diff --git a/x-pack/plugins/security_solution/common/entity_analytics/constants.ts b/x-pack/plugins/security_solution/common/entity_analytics/constants.ts index 08ee2d6afd5179..c0a9567acd09c0 100644 --- a/x-pack/plugins/security_solution/common/entity_analytics/constants.ts +++ b/x-pack/plugins/security_solution/common/entity_analytics/constants.ts @@ -8,3 +8,12 @@ export * from './asset_criticality/constants'; export * from './risk_engine/constants'; export * from './risk_score/constants'; + +export const API_VERSIONS = { + public: { + v1: '2023-10-31', + }, + internal: { + v1: '1', + }, +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts index 9903f6eb2ef78b..da391a9b30432a 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts @@ -31,12 +31,13 @@ import { RISK_ENGINE_DISABLE_URL, RISK_ENGINE_INIT_URL, RISK_ENGINE_PRIVILEGES_URL, - ASSET_CRITICALITY_PRIVILEGES_URL, - ASSET_CRITICALITY_URL, + ASSET_CRITICALITY_INTERNAL_PRIVILEGES_URL, + ASSET_CRITICALITY_PUBLIC_URL, RISK_SCORE_INDEX_STATUS_API_URL, RISK_ENGINE_SETTINGS_URL, - ASSET_CRITICALITY_CSV_UPLOAD_URL, + ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL, RISK_SCORE_ENTITY_CALCULATION_URL, + API_VERSIONS, } from '../../../common/constants'; import type { RiskEngineSettingsResponse } from '../../../common/api/entity_analytics/risk_engine'; import type { SnakeToCamelCase } from '../common/utils'; @@ -127,7 +128,7 @@ export const useEntityAnalyticsRoutes = () => { * Get asset criticality privileges */ const fetchAssetCriticalityPrivileges = () => - http.fetch(ASSET_CRITICALITY_PRIVILEGES_URL, { + http.fetch(ASSET_CRITICALITY_INTERNAL_PRIVILEGES_URL, { version: '1', method: 'GET', }); @@ -140,8 +141,8 @@ export const useEntityAnalyticsRoutes = () => { refresh?: 'wait_for'; } ): Promise => - http.fetch(ASSET_CRITICALITY_URL, { - version: '1', + http.fetch(ASSET_CRITICALITY_PUBLIC_URL, { + version: API_VERSIONS.public.v1, method: 'POST', body: JSON.stringify({ id_value: params.idValue, @@ -154,8 +155,8 @@ export const useEntityAnalyticsRoutes = () => { const deleteAssetCriticality = async ( params: Pick & { refresh?: 'wait_for' } ): Promise<{ deleted: true }> => { - await http.fetch(ASSET_CRITICALITY_URL, { - version: '1', + await http.fetch(ASSET_CRITICALITY_PUBLIC_URL, { + version: API_VERSIONS.public.v1, method: 'DELETE', query: { id_value: params.idValue, id_field: params.idField, refresh: params.refresh }, }); @@ -170,8 +171,8 @@ export const useEntityAnalyticsRoutes = () => { const fetchAssetCriticality = async ( params: Pick ): Promise => { - return http.fetch(ASSET_CRITICALITY_URL, { - version: '1', + return http.fetch(ASSET_CRITICALITY_PUBLIC_URL, { + version: API_VERSIONS.public.v1, method: 'GET', query: { id_value: params.idValue, id_field: params.idField }, }); @@ -185,14 +186,17 @@ export const useEntityAnalyticsRoutes = () => { const body = new FormData(); body.append('file', file); - return http.fetch(ASSET_CRITICALITY_CSV_UPLOAD_URL, { - version: '1', - method: 'POST', - headers: { - 'Content-Type': undefined, // Lets the browser set the appropriate content type - }, - body, - }); + return http.fetch( + ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL, + { + version: API_VERSIONS.public.v1, + method: 'POST', + headers: { + 'Content-Type': undefined, // Lets the browser set the appropriate content type + }, + body, + } + ); }; const getRiskScoreIndexStatus = ({ diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts index 6f1d677d414c56..e2737c6ebe0450 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts @@ -4,13 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { Logger } from '@kbn/core/server'; +import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; +import type { SecuritySolutionRequestHandlerContext } from '../../../../types'; import { - ASSET_CRITICALITY_URL, + ASSET_CRITICALITY_PUBLIC_URL, + ASSET_CRITICALITY_INTERNAL_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, + API_VERSIONS, } from '../../../../../common/constants'; import { DeleteAssetCriticalityRecord } from '../../../../../common/api/entity_analytics/asset_criticality'; import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; @@ -19,64 +22,101 @@ import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setti import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; -export const assetCriticalityDeleteRoute = ( + +type DeleteHandler = ( + context: SecuritySolutionRequestHandlerContext, + request: { + query: DeleteAssetCriticalityRecord; + }, + response: KibanaResponseFactory +) => Promise; + +const handler: (logger: Logger) => DeleteHandler = + (logger) => async (context, request, response) => { + const securitySolution = await context.securitySolution; + + securitySolution.getAuditLogger()?.log({ + message: 'User attempted to un-assign asset criticality from an entity', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_UNASSIGN, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.DELETION, + outcome: AUDIT_OUTCOME.UNKNOWN, + }, + }); + + const siemResponse = buildSiemResponse(response); + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); + + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + await assetCriticalityClient.delete( + { + idField: request.query.id_field, + idValue: request.query.id_value, + }, + request.query.refresh + ); + + return response.ok(); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + }; + +export const assetCriticalityInternalDeleteRoute = ( router: EntityAnalyticsRoutesDeps['router'], logger: Logger ) => { router.versioned .delete({ access: 'internal', - path: ASSET_CRITICALITY_URL, + path: ASSET_CRITICALITY_INTERNAL_URL, options: { tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], }, }) .addVersion( { - version: '1', + version: API_VERSIONS.internal.v1, validate: { request: { query: buildRouteValidationWithZod(DeleteAssetCriticalityRecord), }, }, }, - async (context, request, response) => { - const securitySolution = await context.securitySolution; + handler(logger) + ); +}; - securitySolution.getAuditLogger()?.log({ - message: 'User attempted to un-assign asset criticality from an entity', - event: { - action: AssetCriticalityAuditActions.ASSET_CRITICALITY_UNASSIGN, - category: AUDIT_CATEGORY.DATABASE, - type: AUDIT_TYPE.DELETION, - outcome: AUDIT_OUTCOME.UNKNOWN, +export const assetCriticalityPublicDeleteRoute = ( + router: EntityAnalyticsRoutesDeps['router'], + logger: Logger +) => { + router.versioned + .delete({ + access: 'public', + path: ASSET_CRITICALITY_PUBLIC_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + query: buildRouteValidationWithZod(DeleteAssetCriticalityRecord), }, - }); - - const siemResponse = buildSiemResponse(response); - try { - await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); - await checkAndInitAssetCriticalityResources(context, logger); - - const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); - await assetCriticalityClient.delete( - { - idField: request.query.id_field, - idValue: request.query.id_value, - }, - request.query.refresh - ); - - return response.ok(); - } catch (e) { - const error = transformError(e); - - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); - } - } + }, + }, + handler(logger) ); }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts index fd2a826df117a2..57e52724b94cee 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts @@ -4,13 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { Logger } from '@kbn/core/server'; +import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; +import type { SecuritySolutionRequestHandlerContext } from '../../../../types'; import { - ASSET_CRITICALITY_URL, + ASSET_CRITICALITY_INTERNAL_URL, + ASSET_CRITICALITY_PUBLIC_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, + API_VERSIONS, } from '../../../../../common/constants'; import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; @@ -19,64 +22,99 @@ import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setti import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; -export const assetCriticalityGetRoute = ( +type GetHandler = ( + context: SecuritySolutionRequestHandlerContext, + request: { + query: AssetCriticalityRecordIdParts; + }, + response: KibanaResponseFactory +) => Promise; + +const handler: (logger: Logger) => GetHandler = (logger) => async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); + + const securitySolution = await context.securitySolution; + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + const record = await assetCriticalityClient.get({ + idField: request.query.id_field, + idValue: request.query.id_value, + }); + + if (!record) { + return response.notFound(); + } + + securitySolution.getAuditLogger()?.log({ + message: 'User accessed the criticality level for an entity', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_GET, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.ACCESS, + outcome: AUDIT_OUTCOME.SUCCESS, + }, + }); + + return response.ok({ body: record }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } +}; + +export const assetCriticalityInternalGetRoute = ( router: EntityAnalyticsRoutesDeps['router'], logger: Logger ) => { router.versioned .get({ access: 'internal', - path: ASSET_CRITICALITY_URL, + path: ASSET_CRITICALITY_INTERNAL_URL, options: { tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], }, }) .addVersion( { - version: '1', + version: API_VERSIONS.internal.v1, validate: { request: { query: buildRouteValidationWithZod(AssetCriticalityRecordIdParts), }, }, }, - async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - try { - await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); - await checkAndInitAssetCriticalityResources(context, logger); - - const securitySolution = await context.securitySolution; - const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); - const record = await assetCriticalityClient.get({ - idField: request.query.id_field, - idValue: request.query.id_value, - }); - - if (!record) { - return response.notFound(); - } - - securitySolution.getAuditLogger()?.log({ - message: 'User accessed the criticality level for an entity', - event: { - action: AssetCriticalityAuditActions.ASSET_CRITICALITY_GET, - category: AUDIT_CATEGORY.DATABASE, - type: AUDIT_TYPE.ACCESS, - outcome: AUDIT_OUTCOME.SUCCESS, - }, - }); - - return response.ok({ body: record }); - } catch (e) { - const error = transformError(e); + handler(logger) + ); +}; - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); - } - } +export const assetCriticalityPublicGetRoute = ( + router: EntityAnalyticsRoutesDeps['router'], + logger: Logger +) => { + router.versioned + .get({ + access: 'public', + path: ASSET_CRITICALITY_PUBLIC_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + query: buildRouteValidationWithZod(AssetCriticalityRecordIdParts), + }, + }, + }, + handler(logger) ); }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/privileges.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/privileges.ts index a339ee994c8c24..a3b4c48d828df5 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/privileges.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/privileges.ts @@ -8,9 +8,10 @@ import type { Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { - ASSET_CRITICALITY_PRIVILEGES_URL, + ASSET_CRITICALITY_INTERNAL_PRIVILEGES_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, + API_VERSIONS, } from '../../../../../common/constants'; import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; import { getUserAssetCriticalityPrivileges } from '../get_user_asset_criticality_privileges'; @@ -19,7 +20,7 @@ import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; -export const assetCriticalityPrivilegesRoute = ( +export const assetCriticalityInternalPrivilegesRoute = ( router: EntityAnalyticsRoutesDeps['router'], logger: Logger, getStartServices: EntityAnalyticsRoutesDeps['getStartServices'] @@ -27,14 +28,14 @@ export const assetCriticalityPrivilegesRoute = ( router.versioned .get({ access: 'internal', - path: ASSET_CRITICALITY_PRIVILEGES_URL, + path: ASSET_CRITICALITY_INTERNAL_PRIVILEGES_URL, options: { tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], }, }) .addVersion( { - version: '1', + version: API_VERSIONS.internal.v1, validate: false, }, async (context, request, response) => { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts index 518602a4bc9b7d..c211b1260b6648 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts @@ -4,12 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { assetCriticalityStatusRoute } from './status'; -import { assetCriticalityUpsertRoute } from './upsert'; -import { assetCriticalityGetRoute } from './get'; -import { assetCriticalityDeleteRoute } from './delete'; -import { assetCriticalityPrivilegesRoute } from './privileges'; -import { assetCriticalityCSVUploadRoute } from './upload_csv'; +import { assetCriticalityInternalStatusRoute } from './status'; +import { assetCriticalityPublicUpsertRoute, assetCriticalityInternalUpsertRoute } from './upsert'; +import { assetCriticalityInternalGetRoute, assetCriticalityPublicGetRoute } from './get'; +import { assetCriticalityPublicDeleteRoute, assetCriticalityInternalDeleteRoute } from './delete'; +import { assetCriticalityInternalPrivilegesRoute } from './privileges'; +import { + assetCriticalityInternalCSVUploadRoute, + assetCriticalityPublicCSVUploadRoute, +} from './upload_csv'; import type { EntityAnalyticsRoutesDeps } from '../../types'; export const registerAssetCriticalityRoutes = ({ @@ -18,10 +21,17 @@ export const registerAssetCriticalityRoutes = ({ config, getStartServices, }: EntityAnalyticsRoutesDeps) => { - assetCriticalityStatusRoute(router, logger); - assetCriticalityUpsertRoute(router, logger); - assetCriticalityGetRoute(router, logger); - assetCriticalityDeleteRoute(router, logger); - assetCriticalityPrivilegesRoute(router, logger, getStartServices); - assetCriticalityCSVUploadRoute(router, logger, config, getStartServices); + // Internal routes + assetCriticalityInternalCSVUploadRoute(router, logger, config, getStartServices); + assetCriticalityInternalDeleteRoute(router, logger); + assetCriticalityInternalGetRoute(router, logger); + assetCriticalityInternalPrivilegesRoute(router, logger, getStartServices); + assetCriticalityInternalStatusRoute(router, logger); + assetCriticalityInternalUpsertRoute(router, logger); + + // Public routes + assetCriticalityPublicCSVUploadRoute(router, logger, config, getStartServices); + assetCriticalityPublicDeleteRoute(router, logger); + assetCriticalityPublicGetRoute(router, logger); + assetCriticalityPublicUpsertRoute(router, logger); }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/status.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/status.ts index 27910cfd406317..2afa73ed5a059e 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/status.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/status.ts @@ -9,9 +9,10 @@ import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import type { AssetCriticalityStatusResponse } from '../../../../../common/api/entity_analytics/asset_criticality'; import { - ASSET_CRITICALITY_STATUS_URL, + ASSET_CRITICALITY_INTERNAL_STATUS_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, + API_VERSIONS, } from '../../../../../common/constants'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; import type { EntityAnalyticsRoutesDeps } from '../../types'; @@ -19,53 +20,56 @@ import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setti import { AssetCriticalityAuditActions } from '../audit'; import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; -export const assetCriticalityStatusRoute = ( +export const assetCriticalityInternalStatusRoute = ( router: EntityAnalyticsRoutesDeps['router'], logger: Logger ) => { router.versioned .get({ access: 'internal', - path: ASSET_CRITICALITY_STATUS_URL, + path: ASSET_CRITICALITY_INTERNAL_STATUS_URL, options: { tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], }, }) - .addVersion({ version: '1', validate: {} }, async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - try { - await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); - await checkAndInitAssetCriticalityResources(context, logger); + .addVersion( + { version: API_VERSIONS.internal.v1, validate: {} }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); - const securitySolution = await context.securitySolution; - const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + const securitySolution = await context.securitySolution; + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); - const result = await assetCriticalityClient.getStatus(); + const result = await assetCriticalityClient.getStatus(); - securitySolution.getAuditLogger()?.log({ - message: 'User checked the status of the asset criticality service', - event: { - action: AssetCriticalityAuditActions.ASSET_CRITICALITY_STATUS_GET, - category: AUDIT_CATEGORY.DATABASE, - type: AUDIT_TYPE.ACCESS, - outcome: AUDIT_OUTCOME.UNKNOWN, - }, - }); + securitySolution.getAuditLogger()?.log({ + message: 'User checked the status of the asset criticality service', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_STATUS_GET, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.ACCESS, + outcome: AUDIT_OUTCOME.UNKNOWN, + }, + }); - const body: AssetCriticalityStatusResponse = { - asset_criticality_resources_installed: result.isAssetCriticalityResourcesInstalled, - }; - return response.ok({ - body, - }); - } catch (e) { - const error = transformError(e); + const body: AssetCriticalityStatusResponse = { + asset_criticality_resources_installed: result.isAssetCriticalityResourcesInstalled, + }; + return response.ok({ + body, + }); + } catch (e) { + const error = transformError(e); - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } } - }); + ); }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts index cf4123db487a43..bd0a64fb08da78 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts @@ -4,19 +4,22 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { Logger } from '@kbn/core/server'; +import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { schema } from '@kbn/config-schema'; import Papa from 'papaparse'; import { transformError } from '@kbn/securitysolution-es-utils'; +import type internal from 'stream'; import type { AssetCriticalityCsvUploadResponse } from '../../../../../common/api/entity_analytics'; import { CRITICALITY_CSV_MAX_SIZE_BYTES_WITH_TOLERANCE } from '../../../../../common/entity_analytics/asset_criticality'; import type { ConfigType } from '../../../../config'; -import type { HapiReadableStream } from '../../../../types'; +import type { HapiReadableStream, SecuritySolutionRequestHandlerContext } from '../../../../types'; import { - ASSET_CRITICALITY_CSV_UPLOAD_URL, + ASSET_CRITICALITY_INTERNAL_CSV_UPLOAD_URL, + ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, + API_VERSIONS, } from '../../../../../common/constants'; import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; import { transformCSVToUpsertRecords } from '../transform_csv_to_upsert_records'; @@ -26,18 +29,109 @@ import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; -export const assetCriticalityCSVUploadRoute = ( +type CSVUploadHandler = ( + context: SecuritySolutionRequestHandlerContext, + request: { + body: { file: internal.Stream }; + }, + response: KibanaResponseFactory +) => Promise; + +const handler: ( + logger: Logger, + getStartServices: EntityAnalyticsRoutesDeps['getStartServices'], + config: ConfigType +) => CSVUploadHandler = (logger, getStartServices, config) => async (context, request, response) => { + const { errorRetries, maxBulkRequestBodySizeBytes } = + config.entityAnalytics.assetCriticality.csvUpload; + + const securitySolution = await context.securitySolution; + securitySolution.getAuditLogger()?.log({ + message: 'User attempted to assign many asset criticalities via file upload', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_BULK_UPDATE, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.CREATION, + outcome: AUDIT_OUTCOME.UNKNOWN, + }, + }); + + const start = new Date(); + const siemResponse = buildSiemResponse(response); + const [coreStart] = await getStartServices(); + const telemetry = coreStart.analytics; + + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + const fileStream = request.body.file as HapiReadableStream; + + logger.debug(`Parsing asset criticality CSV file ${fileStream.hapi.filename}`); + + const csvStream = Papa.parse(Papa.NODE_STREAM_INPUT, { + header: false, + dynamicTyping: true, + skipEmptyLines: true, + }); + + const recordsStream = fileStream.pipe(csvStream).pipe(transformCSVToUpsertRecords()); + + const { errors, stats } = await assetCriticalityClient.bulkUpsertFromStream({ + recordsStream, + retries: errorRetries, + flushBytes: maxBulkRequestBodySizeBytes, + }); + const end = new Date(); + + const tookMs = end.getTime() - start.getTime(); + logger.debug(`Asset criticality CSV upload completed in ${tookMs}ms ${JSON.stringify(stats)}`); + + // type assignment here to ensure that the response body stays in sync with the API schema + const resBody: AssetCriticalityCsvUploadResponse = { errors, stats }; + + const [eventType, event] = createAssetCriticalityProcessedFileEvent({ + startTime: start, + endTime: end, + result: stats, + }); + + telemetry.reportEvent(eventType, event); + + return response.ok({ body: resBody }); + } catch (e) { + logger.error(`Error during asset criticality csv upload: ${e}`); + try { + const end = new Date(); + + const [eventType, event] = createAssetCriticalityProcessedFileEvent({ + startTime: start, + endTime: end, + }); + + telemetry.reportEvent(eventType, event); + } catch (error) { + logger.error(`Error reporting telemetry event: ${error}`); + } + + const error = transformError(e); + return siemResponse.error({ + statusCode: error.statusCode, + body: error.message, + }); + } +}; + +export const assetCriticalityInternalCSVUploadRoute = ( router: EntityAnalyticsRoutesDeps['router'], logger: Logger, config: ConfigType, getStartServices: EntityAnalyticsRoutesDeps['getStartServices'] ) => { - const { errorRetries, maxBulkRequestBodySizeBytes } = - config.entityAnalytics.assetCriticality.csvUpload; router.versioned .post({ access: 'internal', - path: ASSET_CRITICALITY_CSV_UPLOAD_URL, + path: ASSET_CRITICALITY_INTERNAL_CSV_UPLOAD_URL, options: { tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], body: { @@ -49,7 +143,7 @@ export const assetCriticalityCSVUploadRoute = ( }) .addVersion( { - version: '1', + version: API_VERSIONS.internal.v1, validate: { request: { body: schema.object({ @@ -58,84 +152,39 @@ export const assetCriticalityCSVUploadRoute = ( }, }, }, - async (context, request, response) => { - const securitySolution = await context.securitySolution; - securitySolution.getAuditLogger()?.log({ - message: 'User attempted to assign many asset criticalities via file upload', - event: { - action: AssetCriticalityAuditActions.ASSET_CRITICALITY_BULK_UPDATE, - category: AUDIT_CATEGORY.DATABASE, - type: AUDIT_TYPE.CREATION, - outcome: AUDIT_OUTCOME.UNKNOWN, + handler(logger, getStartServices, config) + ); +}; +export const assetCriticalityPublicCSVUploadRoute = ( + router: EntityAnalyticsRoutesDeps['router'], + logger: Logger, + config: ConfigType, + getStartServices: EntityAnalyticsRoutesDeps['getStartServices'] +) => { + router.versioned + .post({ + access: 'public', + path: ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + body: { + output: 'stream', + accepts: 'multipart/form-data', + maxBytes: CRITICALITY_CSV_MAX_SIZE_BYTES_WITH_TOLERANCE, + }, + }, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + body: schema.object({ + file: schema.stream(), + }), }, - }); - - const start = new Date(); - const siemResponse = buildSiemResponse(response); - const [coreStart] = await getStartServices(); - const telemetry = coreStart.analytics; - - try { - await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); - await checkAndInitAssetCriticalityResources(context, logger); - const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); - const fileStream = request.body.file as HapiReadableStream; - - logger.debug(`Parsing asset criticality CSV file ${fileStream.hapi.filename}`); - - const csvStream = Papa.parse(Papa.NODE_STREAM_INPUT, { - header: false, - dynamicTyping: true, - skipEmptyLines: true, - }); - - const recordsStream = fileStream.pipe(csvStream).pipe(transformCSVToUpsertRecords()); - - const { errors, stats } = await assetCriticalityClient.bulkUpsertFromStream({ - recordsStream, - retries: errorRetries, - flushBytes: maxBulkRequestBodySizeBytes, - }); - const end = new Date(); - - const tookMs = end.getTime() - start.getTime(); - logger.debug( - `Asset criticality CSV upload completed in ${tookMs}ms ${JSON.stringify(stats)}` - ); - - // type assignment here to ensure that the response body stays in sync with the API schema - const resBody: AssetCriticalityCsvUploadResponse = { errors, stats }; - - const [eventType, event] = createAssetCriticalityProcessedFileEvent({ - startTime: start, - endTime: end, - result: stats, - }); - - telemetry.reportEvent(eventType, event); - - return response.ok({ body: resBody }); - } catch (e) { - logger.error(`Error during asset criticality csv upload: ${e}`); - try { - const end = new Date(); - - const [eventType, event] = createAssetCriticalityProcessedFileEvent({ - startTime: start, - endTime: end, - }); - - telemetry.reportEvent(eventType, event); - } catch (error) { - logger.error(`Error reporting telemetry event: ${error}`); - } - - const error = transformError(e); - return siemResponse.error({ - statusCode: error.statusCode, - body: error.message, - }); - } - } + }, + }, + handler(logger, getStartServices, config) ); }; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts index 8a6d4756959624..d367a1f8bd4d38 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts @@ -4,13 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { Logger } from '@kbn/core/server'; +import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; +import type { SecuritySolutionRequestHandlerContext } from '../../../../types'; import { - ASSET_CRITICALITY_URL, + ASSET_CRITICALITY_PUBLIC_URL, + ASSET_CRITICALITY_INTERNAL_URL, APP_ID, ENABLE_ASSET_CRITICALITY_SETTING, + API_VERSIONS, } from '../../../../../common/constants'; import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; @@ -19,69 +22,106 @@ import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setting_enabled'; -export const assetCriticalityUpsertRoute = ( + +type UpsertHandler = ( + context: SecuritySolutionRequestHandlerContext, + request: { + body: CreateAssetCriticalityRecord; + }, + response: KibanaResponseFactory +) => Promise; + +const handler: (logger: Logger) => UpsertHandler = + (logger) => async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); + + const securitySolution = await context.securitySolution; + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + + const assetCriticalityRecord = { + idField: request.body.id_field, + idValue: request.body.id_value, + criticalityLevel: request.body.criticality_level, + }; + + const result = await assetCriticalityClient.upsert( + assetCriticalityRecord, + request.body.refresh + ); + + securitySolution.getAuditLogger()?.log({ + message: 'User attempted to assign the asset criticality level for an entity', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_UPDATE, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.CREATION, + outcome: AUDIT_OUTCOME.UNKNOWN, + }, + }); + + return response.ok({ + body: result, + }); + } catch (e) { + const error = transformError(e); + + return siemResponse.error({ + statusCode: error.statusCode, + body: { message: error.message, full_error: JSON.stringify(e) }, + bypassErrorFormat: true, + }); + } + }; + +export const assetCriticalityInternalUpsertRoute = ( router: EntityAnalyticsRoutesDeps['router'], logger: Logger ) => { router.versioned .post({ access: 'internal', - path: ASSET_CRITICALITY_URL, + path: ASSET_CRITICALITY_INTERNAL_URL, options: { tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], }, }) .addVersion( { - version: '1', + version: API_VERSIONS.internal.v1, validate: { request: { body: buildRouteValidationWithZod(CreateAssetCriticalityRecord), }, }, }, - async (context, request, response) => { - const siemResponse = buildSiemResponse(response); - try { - await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); - await checkAndInitAssetCriticalityResources(context, logger); - - const securitySolution = await context.securitySolution; - const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); - - const assetCriticalityRecord = { - idField: request.body.id_field, - idValue: request.body.id_value, - criticalityLevel: request.body.criticality_level, - }; - - const result = await assetCriticalityClient.upsert( - assetCriticalityRecord, - request.body.refresh - ); - - securitySolution.getAuditLogger()?.log({ - message: 'User attempted to assign the asset criticality level for an entity', - event: { - action: AssetCriticalityAuditActions.ASSET_CRITICALITY_UPDATE, - category: AUDIT_CATEGORY.DATABASE, - type: AUDIT_TYPE.CREATION, - outcome: AUDIT_OUTCOME.UNKNOWN, - }, - }); - - return response.ok({ - body: result, - }); - } catch (e) { - const error = transformError(e); + handler(logger) + ); +}; - return siemResponse.error({ - statusCode: error.statusCode, - body: { message: error.message, full_error: JSON.stringify(e) }, - bypassErrorFormat: true, - }); - } - } +export const assetCriticalityPublicUpsertRoute = ( + router: EntityAnalyticsRoutesDeps['router'], + logger: Logger +) => { + router.versioned + .post({ + access: 'public', + path: ASSET_CRITICALITY_PUBLIC_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + body: buildRouteValidationWithZod(CreateAssetCriticalityRecord), + }, + }, + }, + handler(logger) ); }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts index 3a46aa56ef6140..da786269519db9 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts @@ -11,11 +11,12 @@ import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST, } from '@kbn/core-http-common'; import { - ASSET_CRITICALITY_STATUS_URL, - ASSET_CRITICALITY_URL, - ASSET_CRITICALITY_PRIVILEGES_URL, - ASSET_CRITICALITY_CSV_UPLOAD_URL, + ASSET_CRITICALITY_PUBLIC_URL, + ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL, + ASSET_CRITICALITY_INTERNAL_STATUS_URL, + ASSET_CRITICALITY_INTERNAL_PRIVILEGES_URL, ENABLE_ASSET_CRITICALITY_SETTING, + API_VERSIONS, } from '@kbn/security-solution-plugin/common/constants'; import type { AssetCriticalityRecord } from '@kbn/security-solution-plugin/common/api/entity_analytics'; import type { Client } from '@elastic/elasticsearch'; @@ -109,9 +110,9 @@ export const assetCriticalityRouteHelpersFactory = ( ) => ({ status: async () => await supertest - .get(routeWithNamespace(ASSET_CRITICALITY_STATUS_URL, namespace)) + .get(routeWithNamespace(ASSET_CRITICALITY_INTERNAL_STATUS_URL, namespace)) .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(ELASTIC_HTTP_VERSION_HEADER, API_VERSIONS.internal.v1) .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send() .expect(200), @@ -120,9 +121,9 @@ export const assetCriticalityRouteHelpersFactory = ( { expectStatusCode }: { expectStatusCode: number } = { expectStatusCode: 200 } ) => await supertest - .post(routeWithNamespace(ASSET_CRITICALITY_URL, namespace)) + .post(routeWithNamespace(ASSET_CRITICALITY_PUBLIC_URL, namespace)) .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(ELASTIC_HTTP_VERSION_HEADER, API_VERSIONS.public.v1) .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(body) .expect(expectStatusCode), @@ -132,11 +133,11 @@ export const assetCriticalityRouteHelpersFactory = ( { expectStatusCode }: { expectStatusCode: number } = { expectStatusCode: 200 } ) => { const qs = querystring.stringify({ id_field: idField, id_value: idValue }); - const route = `${routeWithNamespace(ASSET_CRITICALITY_URL, namespace)}?${qs}`; + const route = `${routeWithNamespace(ASSET_CRITICALITY_PUBLIC_URL, namespace)}?${qs}`; return supertest .delete(route) .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(ELASTIC_HTTP_VERSION_HEADER, API_VERSIONS.public.v1) .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .expect(expectStatusCode); }, @@ -146,11 +147,11 @@ export const assetCriticalityRouteHelpersFactory = ( { expectStatusCode }: { expectStatusCode: number } = { expectStatusCode: 200 } ) => { const qs = querystring.stringify({ id_field: idField, id_value: idValue }); - const route = `${routeWithNamespace(ASSET_CRITICALITY_URL, namespace)}?${qs}`; + const route = `${routeWithNamespace(ASSET_CRITICALITY_PUBLIC_URL, namespace)}?${qs}`; return supertest .get(route) .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(ELASTIC_HTTP_VERSION_HEADER, API_VERSIONS.public.v1) .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .expect(expectStatusCode); }, @@ -160,9 +161,9 @@ export const assetCriticalityRouteHelpersFactory = ( ) => { const file = fileContent instanceof Buffer ? fileContent : Buffer.from(fileContent); return supertest - .post(routeWithNamespace(ASSET_CRITICALITY_CSV_UPLOAD_URL, namespace)) + .post(routeWithNamespace(ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL, namespace)) .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(ELASTIC_HTTP_VERSION_HEADER, API_VERSIONS.public.v1) .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .attach('file', file, { filename: 'asset_criticality.csv' }) .expect(expectStatusCode); @@ -175,9 +176,9 @@ export const assetCriticalityRouteHelpersFactoryNoAuth = ( ) => ({ privilegesForUser: async ({ username, password }: { username: string; password: string }) => await supertestWithoutAuth - .get(ASSET_CRITICALITY_PRIVILEGES_URL) + .get(ASSET_CRITICALITY_INTERNAL_PRIVILEGES_URL) .auth(username, password) - .set('elastic-api-version', '1') + .set('elastic-api-version', API_VERSIONS.internal.v1) .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send() .expect(200), From 051b91a47ffcbf68a01bdae869375bcd4c8fe610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 18 Jun 2024 12:18:07 +0200 Subject: [PATCH 020/123] [Discover] Add logs source and document contexts (#184601) ## :memo: Summary This PR adds basic implementations for resolving "logs" data source and document contexts to their respective profiles. Due to the limited set of profile customization points the new profiles are empty. - closes #184079 - closes #184080 ## :mag: Implementation details - In order to organize these and future profiles this PR introduces the `profile_providers` folder in `context_awareness`. - For a more structured organization, utilities for resolving logs sources have been moved/implemented in the `@kbn/discover-utils` and `@kbn/data-view-utils` packages. - The code ownership for the two logs profiles is shared between the data discovery team and the obs ux logs team. ### Document Level Logs Resolution The document logs context resolution is performed with the following criteria, as far as one complies, the context will be evaluated as a match: - The `data_stream.type` field exists on the document and it's equal to `logs` - The document contains any field from the [ECS Log field set](https://www.elastic.co/guide/en/ecs/current/ecs-log.html) (fields staring with `log.`) - The `_index` field exists and tests positive against the allowed indices from the [built-in definition/ settings](https://github.com/elastic/kibana/pull/184601/files#diff-5e1646fa4ec758a92aa38910dc047b18cb826e287a36b43e811eb5fc7a3b0fe9R28). ### Data Source Logs Resolution The data source logs context resolution is performed with the following criteria, as far as one complies, the context will be evaluated as a match: - Being the source of a data view type, the related index tests positive against the allowed indices from the [built-in definition/ settings](https://github.com/elastic/kibana/pull/184601/files#diff-5e1646fa4ec758a92aa38910dc047b18cb826e287a36b43e811eb5fc7a3b0fe9R28). - Being the source of a ES|QL query type, the related index extracted from the query tests positive against the allowed indices from the [built-in definition/ settings](https://github.com/elastic/kibana/pull/184601/files#diff-5e1646fa4ec758a92aa38910dc047b18cb826e287a36b43e811eb5fc7a3b0fe9R28). ## :female_detective: Review notes > [!NOTE] > Notes in this format have been left through the PR to give additional context about some choices, any further feedback is welcome --------- Co-authored-by: Davis McPhee Co-authored-by: Marco Antonio Ghiani Co-authored-by: Marco Antonio Ghiani Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kerry Gallagher --- packages/kbn-data-view-utils/index.ts | 3 + .../utils/create_regexp_pattern_from.test.ts | 68 +++++++ .../src/utils/create_regexp_pattern_from.ts | 12 +- .../test_pattern_against_allowed_list.test.ts | 24 +++ .../test_pattern_against_allowed_list.ts | 22 +++ packages/kbn-discover-utils/index.ts | 4 + .../src/data_types/logs/index.ts | 2 + .../data_types/logs/logs_context_service.ts | 45 +++++ packages/kbn-discover-utils/tsconfig.json | 1 + .../discover/common/data_sources/utils.ts | 8 + src/plugins/discover/public/build_services.ts | 2 +- .../context_awareness/__mocks__/index.ts | 4 + .../log_document_profile/index.ts | 9 + .../log_document_profile/profile.test.ts | 78 ++++++++ .../log_document_profile/profile.ts | 57 ++++++ .../logs_data_source_profile/index.ts | 9 + .../logs_data_source_profile/profile.test.ts | 78 ++++++++ .../logs_data_source_profile/profile.ts | 50 +++++ .../profiles/profile_provider_services.ts | 27 +++ src/plugins/discover/public/index.ts | 2 +- src/plugins/discover/public/plugin.tsx | 176 ++---------------- src/plugins/discover/public/types.ts | 170 +++++++++++++++++ .../utils/initialize_kbn_url_tracking.test.ts | 2 +- .../utils/initialize_kbn_url_tracking.ts | 2 +- .../apm/public/plugin.ts | 2 +- .../logs_explorer/common/constants.ts | 3 - .../data_views/models/data_view_descriptor.ts | 30 +-- .../logs_explorer/common/ui_settings.ts | 4 +- .../logs_explorer/tsconfig.json | 1 + .../data_source_selector.ts | 2 +- 30 files changed, 696 insertions(+), 201 deletions(-) create mode 100644 packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.test.ts rename x-pack/plugins/observability_solution/logs_explorer/common/data_views/utils.ts => packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.ts (52%) create mode 100644 packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.test.ts create mode 100644 packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.ts create mode 100644 packages/kbn-discover-utils/src/data_types/logs/logs_context_service.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/index.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.test.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/index.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts create mode 100644 src/plugins/discover/public/context_awareness/profiles/profile_provider_services.ts create mode 100644 src/plugins/discover/public/types.ts diff --git a/packages/kbn-data-view-utils/index.ts b/packages/kbn-data-view-utils/index.ts index c78869a471cb0e..1c881dbdacf79f 100644 --- a/packages/kbn-data-view-utils/index.ts +++ b/packages/kbn-data-view-utils/index.ts @@ -7,3 +7,6 @@ */ export * from './src/constants'; + +export { createRegExpPatternFrom } from './src/utils/create_regexp_pattern_from'; +export { testPatternAgainstAllowedList } from './src/utils/test_pattern_against_allowed_list'; diff --git a/packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.test.ts b/packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.test.ts new file mode 100644 index 00000000000000..24975576582d6e --- /dev/null +++ b/packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.test.ts @@ -0,0 +1,68 @@ +/* + * 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 { createRegExpPatternFrom } from './create_regexp_pattern_from'; + +describe('createRegExpPatternFrom should create a regular expression starting from a string that', () => { + const regExpPattern = createRegExpPatternFrom('logs'); + + it('tests positive for single index patterns starting with the passed base pattern', () => { + expect('logs*').toMatch(regExpPattern); + expect('logs-*').toMatch(regExpPattern); + expect('logs-*-*').toMatch(regExpPattern); + expect('logs-system.syslog-*').toMatch(regExpPattern); + + expect('logss*').not.toMatch(regExpPattern); + expect('logss-*').not.toMatch(regExpPattern); + expect('metrics*').not.toMatch(regExpPattern); + expect('metrics-*').not.toMatch(regExpPattern); + }); + + it('tests positive for single index patterns containing the passed base pattern', () => { + expect('foo-logs*').toMatch(regExpPattern); + expect('foo-logs-*').toMatch(regExpPattern); + expect('foo-logs-*-*').toMatch(regExpPattern); + expect('foo-logs-system.syslog-*').toMatch(regExpPattern); + expect('.ds-kibana_sample_data_logs-2024.06.13-000001').toMatch(regExpPattern); + + expect('foo-logss*').not.toMatch(regExpPattern); + expect('foo-logss-*').not.toMatch(regExpPattern); + expect('foo-metrics*').not.toMatch(regExpPattern); + expect('foo-metrics-*').not.toMatch(regExpPattern); + }); + + it('tests positive for single index patterns with CCS prefixes', () => { + expect('cluster1:logs-*').toMatch(regExpPattern); + expect('cluster1:logs-*-*').toMatch(regExpPattern); + expect('cluster1:logs-system.syslog-*').toMatch(regExpPattern); + expect('cluster1:logs-system.syslog-default').toMatch(regExpPattern); + + expect('cluster1:logss*').not.toMatch(regExpPattern); + expect('cluster1:logss-*').not.toMatch(regExpPattern); + expect('cluster1:metrics*').not.toMatch(regExpPattern); + expect('cluster1:metrics-*').not.toMatch(regExpPattern); + }); + + it('tests positive for multiple index patterns comma-separated if all of them individually match the criteria', () => { + expect('logs-*,cluster1:logs-*').toMatch(regExpPattern); + expect('cluster1:logs-*,cluster2:logs-*').toMatch(regExpPattern); + expect('*:logs-system.syslog-*,*:logs-system.errors-*').toMatch(regExpPattern); + + expect('*:metrics-system.syslog-*,logs-system.errors-*').not.toMatch(regExpPattern); + }); + + it('tests positive for patterns with trailing commas', () => { + expect('logs-*,').toMatch(regExpPattern); + expect('cluster1:logs-*,logs-*,').toMatch(regExpPattern); + }); + + it('tests negative for patterns with spaces and unexpected commas', () => { + expect('cluster1:logs-*,clust,er2:logs-*').not.toMatch(regExpPattern); + expect('cluster1:logs-*, cluster2:logs-*').not.toMatch(regExpPattern); + }); +}); diff --git a/x-pack/plugins/observability_solution/logs_explorer/common/data_views/utils.ts b/packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.ts similarity index 52% rename from x-pack/plugins/observability_solution/logs_explorer/common/data_views/utils.ts rename to packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.ts index 4b316ba1d5877d..c240f2f8936884 100644 --- a/x-pack/plugins/observability_solution/logs_explorer/common/data_views/utils.ts +++ b/packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.ts @@ -1,15 +1,17 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 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 buildIndexPatternRegExp = (basePatterns: string[]) => { +export const createRegExpPatternFrom = (basePatterns: string | string[]) => { + const patterns = Array.isArray(basePatterns) ? basePatterns : [basePatterns]; // Create the base patterns union with strict boundaries - const basePatternGroup = `\\b(${basePatterns.join('|')})\\b([^,\\s]+)?`; + const basePatternGroup = `[^,\\s]*(\\b|_)(${patterns.join('|')})(\\b|_)([^,\\s]*)?`; // Apply base patterns union for local and remote clusters - const localAndRemotePatternGroup = `((${basePatternGroup})|([^:,\\s]+:${basePatternGroup}))`; + const localAndRemotePatternGroup = `((${basePatternGroup})|([^:,\\s]*:${basePatternGroup}))`; // Handle trailing comma and multiple pattern concatenation return new RegExp(`^${localAndRemotePatternGroup}(,${localAndRemotePatternGroup})*(,$|$)`, 'i'); }; diff --git a/packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.test.ts b/packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.test.ts new file mode 100644 index 00000000000000..e72038771b0360 --- /dev/null +++ b/packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.test.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { testPatternAgainstAllowedList } from './test_pattern_against_allowed_list'; + +describe('testPatternAgainstAllowedList', () => { + const allowedList = ['foo-logs-bar', /^\b(logs)\b([^,\s]*)/i]; + + it('should return true if the passed input matches any string or regexp of the passed list', () => { + expect(testPatternAgainstAllowedList(allowedList)('logs-*')).toBeTruthy(); + expect(testPatternAgainstAllowedList(allowedList)('logs-*-*')).toBeTruthy(); + expect(testPatternAgainstAllowedList(allowedList)('logs-system.syslog-*')).toBeTruthy(); + expect(testPatternAgainstAllowedList(allowedList)('foo-logs-bar')).toBeTruthy(); + + expect(testPatternAgainstAllowedList(allowedList)('logss-*')).toBeFalsy(); + expect(testPatternAgainstAllowedList(allowedList)('metrics*')).toBeFalsy(); + expect(testPatternAgainstAllowedList(allowedList)('metrics-*')).toBeFalsy(); + }); +}); diff --git a/packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.ts b/packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.ts new file mode 100644 index 00000000000000..62cbd4db9d0fe1 --- /dev/null +++ b/packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 testPatternAgainstAllowedList = + (allowedList: Array) => (value: string) => { + for (const allowedItem of allowedList) { + const isMatchingString = typeof allowedItem === 'string' && value === allowedItem; + const isMatchingRegExp = allowedItem instanceof RegExp && allowedItem.test(value); + + if (isMatchingString || isMatchingRegExp) { + return true; + } + } + + // If no match is found in the allowedList, return false + return false; + }; diff --git a/packages/kbn-discover-utils/index.ts b/packages/kbn-discover-utils/index.ts index 7a7fedfb5f1e33..1656a36a91da28 100644 --- a/packages/kbn-discover-utils/index.ts +++ b/packages/kbn-discover-utils/index.ts @@ -10,6 +10,7 @@ export { CONTEXT_DEFAULT_SIZE_SETTING, CONTEXT_STEP_SETTING, CONTEXT_TIE_BREAKER_FIELDS_SETTING, + DEFAULT_ALLOWED_LOGS_BASE_PATTERNS, DEFAULT_COLUMNS_SETTING, DOC_HIDE_TIME_COLUMN_SETTING, DOC_TABLE_LEGACY, @@ -30,6 +31,7 @@ export { IgnoredReason, buildDataTableRecord, buildDataTableRecordList, + createLogsContextService, fieldConstants, formatFieldValue, formatHit, @@ -43,4 +45,6 @@ export { usePager, } from './src'; +export type { LogsContextService } from './src'; + export * from './src/types'; diff --git a/packages/kbn-discover-utils/src/data_types/logs/index.ts b/packages/kbn-discover-utils/src/data_types/logs/index.ts index 21d54fd754a3e8..f1147d7aa071b8 100644 --- a/packages/kbn-discover-utils/src/data_types/logs/index.ts +++ b/packages/kbn-discover-utils/src/data_types/logs/index.ts @@ -8,3 +8,5 @@ export * from './types'; export * from './utils'; + +export * from './logs_context_service'; diff --git a/packages/kbn-discover-utils/src/data_types/logs/logs_context_service.ts b/packages/kbn-discover-utils/src/data_types/logs/logs_context_service.ts new file mode 100644 index 00000000000000..6eecd1beff4912 --- /dev/null +++ b/packages/kbn-discover-utils/src/data_types/logs/logs_context_service.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 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 { createRegExpPatternFrom, testPatternAgainstAllowedList } from '@kbn/data-view-utils'; + +export interface LogsContextService { + isLogsIndexPattern(indexPattern: unknown): boolean; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface LogsContextServiceDeps { + // We will probably soon add uiSettings as a dependency + // to consume user configured indices +} + +export const DEFAULT_ALLOWED_LOGS_BASE_PATTERNS = [ + 'log', + 'logs', + 'logstash', + 'auditbeat', + 'filebeat', + 'winlogbeat', +]; + +export const createLogsContextService = (_deps: LogsContextServiceDeps = {}) => { + // This is initially an hard-coded set of well-known base patterns, + // we can extend this allowed list with any setting coming from uiSettings + const ALLOWED_LOGS_DATA_SOURCES = [createRegExpPatternFrom(DEFAULT_ALLOWED_LOGS_BASE_PATTERNS)]; + + const isLogsIndexPattern = (indexPattern: unknown) => { + return ( + typeof indexPattern === 'string' && + testPatternAgainstAllowedList(ALLOWED_LOGS_DATA_SOURCES)(indexPattern) + ); + }; + + return { + isLogsIndexPattern, + }; +}; diff --git a/packages/kbn-discover-utils/tsconfig.json b/packages/kbn-discover-utils/tsconfig.json index 64453f8245afea..bbd35127c43fb7 100644 --- a/packages/kbn-discover-utils/tsconfig.json +++ b/packages/kbn-discover-utils/tsconfig.json @@ -18,6 +18,7 @@ "kbn_references": [ "@kbn/data-service", "@kbn/data-views-plugin", + "@kbn/data-view-utils", "@kbn/es-query", "@kbn/field-formats-plugin", "@kbn/field-types", diff --git a/src/plugins/discover/common/data_sources/utils.ts b/src/plugins/discover/common/data_sources/utils.ts index 4bf8b0fcf3678a..f876d0b4c06f29 100644 --- a/src/plugins/discover/common/data_sources/utils.ts +++ b/src/plugins/discover/common/data_sources/utils.ts @@ -25,3 +25,11 @@ export const isDataSourceType = ( dataSource: DiscoverDataSource | undefined, type: T ): dataSource is Extract => dataSource?.type === type; + +export const isDataViewSource = ( + dataSource: DiscoverDataSource | undefined +): dataSource is DataViewDataSource => isDataSourceType(dataSource, DataSourceType.DataView); + +export const isEsqlSource = ( + dataSource: DiscoverDataSource | undefined +): dataSource is EsqlDataSource => isDataSourceType(dataSource, DataSourceType.Esql); diff --git a/src/plugins/discover/public/build_services.ts b/src/plugins/discover/public/build_services.ts index 519d6a36fb5287..e1ccef0105d482 100644 --- a/src/plugins/discover/public/build_services.ts +++ b/src/plugins/discover/public/build_services.ts @@ -56,7 +56,7 @@ import { memoize, noop } from 'lodash'; import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import type { AiopsPluginStart } from '@kbn/aiops-plugin/public'; import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public'; -import type { DiscoverStartPlugins } from './plugin'; +import type { DiscoverStartPlugins } from './types'; import type { DiscoverContextAppLocator } from './application/context/services/locator'; import type { DiscoverSingleDocLocator } from './application/doc/locator'; import type { DiscoverAppLocator } from '../common'; diff --git a/src/plugins/discover/public/context_awareness/__mocks__/index.ts b/src/plugins/discover/public/context_awareness/__mocks__/index.ts index b493ff43bfbca0..0e104b6a026362 100644 --- a/src/plugins/discover/public/context_awareness/__mocks__/index.ts +++ b/src/plugins/discover/public/context_awareness/__mocks__/index.ts @@ -19,6 +19,7 @@ import { RootProfileService, SolutionType, } from '../profiles'; +import { createProfileProviderServices } from '../profiles/profile_provider_services'; import { ProfilesManager } from '../profiles_manager'; export const createContextAwarenessMocks = () => { @@ -107,6 +108,8 @@ export const createContextAwarenessMocks = () => { documentProfileServiceMock ); + const profileProviderServices = createProfileProviderServices(); + return { rootProfileProviderMock, dataSourceProfileProviderMock, @@ -114,5 +117,6 @@ export const createContextAwarenessMocks = () => { contextRecordMock, contextRecordMock2, profilesManagerMock, + profileProviderServices, }; }; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/index.ts new file mode 100644 index 00000000000000..c31d26b4a8989d --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { createLogDocumentProfileProvider } from './profile'; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.test.ts b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.test.ts new file mode 100644 index 00000000000000..6514eb699e553d --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.test.ts @@ -0,0 +1,78 @@ +/* + * 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 { buildDataTableRecord } from '@kbn/discover-utils'; +import { DocumentType } from '../../profiles'; +import { createContextAwarenessMocks } from '../../__mocks__'; +import { createLogDocumentProfileProvider } from './profile'; + +const mockServices = createContextAwarenessMocks().profileProviderServices; + +describe('logDocumentProfileProvider', () => { + const logDocumentProfileProvider = createLogDocumentProfileProvider(mockServices); + const RESOLUTION_MATCH = { + isMatch: true, + context: { + type: DocumentType.Log, + }, + }; + const RESOLUTION_MISMATCH = { + isMatch: false, + }; + + it('matches records with the correct data stream type', () => { + expect( + logDocumentProfileProvider.resolve({ + record: buildMockRecord('logs-2000-01-01', { + 'data_stream.type': ['logs'], + }), + }) + ).toEqual(RESOLUTION_MATCH); + }); + + it('matches records with fields prefixed with "log."', () => { + expect( + logDocumentProfileProvider.resolve({ + record: buildMockRecord('logs-2000-01-01', { + 'log.level': ['INFO'], + }), + }) + ).toEqual(RESOLUTION_MATCH); + }); + + it('matches records with indices matching the allowed pattern', () => { + expect( + logDocumentProfileProvider.resolve({ + record: buildMockRecord('logs-2000-01-01'), + }) + ).toEqual(RESOLUTION_MATCH); + expect( + logDocumentProfileProvider.resolve({ + record: buildMockRecord('remote_cluster:filebeat'), + }) + ).toEqual(RESOLUTION_MATCH); + }); + + it('does not match records with neither characteristic', () => { + expect( + logDocumentProfileProvider.resolve({ + record: buildMockRecord('another-index'), + }) + ).toEqual(RESOLUTION_MISMATCH); + }); +}); + +const buildMockRecord = (index: string, fields: Record = {}) => + buildDataTableRecord({ + _id: '', + _index: index, + fields: { + _index: index, + ...fields, + }, + }); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts new file mode 100644 index 00000000000000..7c1da0cef45cd4 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts @@ -0,0 +1,57 @@ +/* + * 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 { DataTableRecord } from '@kbn/discover-utils'; +import { DocumentProfileProvider, DocumentType } from '../../profiles'; +import { ProfileProviderServices } from '../../profiles/profile_provider_services'; + +export const createLogDocumentProfileProvider = ( + services: ProfileProviderServices +): DocumentProfileProvider => ({ + profileId: 'log-document-profile', + profile: {}, + resolve: ({ record }) => { + const isLogRecord = getIsLogRecord(record, services.logsContextService.isLogsIndexPattern); + + if (!isLogRecord) { + return { isMatch: false }; + } + + return { + isMatch: true, + context: { + type: DocumentType.Log, + }, + }; + }, +}); + +const getIsLogRecord = ( + record: DataTableRecord, + isLogsIndexPattern: ProfileProviderServices['logsContextService']['isLogsIndexPattern'] +) => { + return ( + getDataStreamType(record).includes('logs') || + hasFieldsWithPrefix('log.')(record) || + getIndices(record).some(isLogsIndexPattern) + ); +}; + +const getFieldValues = + (field: string) => + (record: DataTableRecord): unknown[] => { + const value = record.flattened[field]; + return Array.isArray(value) ? value : [value]; + }; + +const getDataStreamType = getFieldValues('data_stream.type'); +const getIndices = getFieldValues('_index'); + +const hasFieldsWithPrefix = (prefix: string) => (record: DataTableRecord) => { + return Object.keys(record.flattened).some((field) => field.startsWith(prefix)); +}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/index.ts new file mode 100644 index 00000000000000..f7d780da6ef020 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { createLogsDataSourceProfileProvider } from './profile'; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts new file mode 100644 index 00000000000000..e6b99802235cf9 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts @@ -0,0 +1,78 @@ +/* + * 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 { createStubIndexPattern } from '@kbn/data-views-plugin/common/data_view.stub'; +import { createDataViewDataSource, createEsqlDataSource } from '../../../../common/data_sources'; +import { DataSourceCategory } from '../../profiles'; +import { createContextAwarenessMocks } from '../../__mocks__'; +import { createLogsDataSourceProfileProvider } from './profile'; + +const mockServices = createContextAwarenessMocks().profileProviderServices; + +describe('logsDataSourceProfileProvider', () => { + const logsDataSourceProfileProvider = createLogsDataSourceProfileProvider(mockServices); + const VALID_INDEX_PATTERN = 'logs-nginx.access-*'; + const MIXED_INDEX_PATTERN = 'logs-nginx.access-*,metrics-*'; + const INVALID_INDEX_PATTERN = 'my_source-access-*'; + + const RESOLUTION_MATCH = { + isMatch: true, + context: { category: DataSourceCategory.Logs }, + }; + const RESOLUTION_MISMATCH = { + isMatch: false, + }; + + it('should match ES|QL sources with an allowed index pattern in its query', () => { + expect( + logsDataSourceProfileProvider.resolve({ + dataSource: createEsqlDataSource(), + query: { esql: `from ${VALID_INDEX_PATTERN}` }, + }) + ).toEqual(RESOLUTION_MATCH); + }); + + it('should NOT match ES|QL sources with a mixed or not allowed index pattern in its query', () => { + expect( + logsDataSourceProfileProvider.resolve({ + dataSource: createEsqlDataSource(), + query: { esql: `from ${INVALID_INDEX_PATTERN}` }, + }) + ).toEqual(RESOLUTION_MISMATCH); + expect( + logsDataSourceProfileProvider.resolve({ + dataSource: createEsqlDataSource(), + query: { esql: `from ${MIXED_INDEX_PATTERN}` }, + }) + ).toEqual(RESOLUTION_MISMATCH); + }); + + it('should match data view sources with an allowed index pattern', () => { + expect( + logsDataSourceProfileProvider.resolve({ + dataSource: createDataViewDataSource({ dataViewId: VALID_INDEX_PATTERN }), + dataView: createStubIndexPattern({ spec: { title: VALID_INDEX_PATTERN } }), + }) + ).toEqual(RESOLUTION_MATCH); + }); + + it('should NOT match data view sources with a mixed or not allowed index pattern', () => { + expect( + logsDataSourceProfileProvider.resolve({ + dataSource: createDataViewDataSource({ dataViewId: INVALID_INDEX_PATTERN }), + dataView: createStubIndexPattern({ spec: { title: INVALID_INDEX_PATTERN } }), + }) + ).toEqual(RESOLUTION_MISMATCH); + expect( + logsDataSourceProfileProvider.resolve({ + dataSource: createDataViewDataSource({ dataViewId: MIXED_INDEX_PATTERN }), + dataView: createStubIndexPattern({ spec: { title: MIXED_INDEX_PATTERN } }), + }) + ).toEqual(RESOLUTION_MISMATCH); + }); +}); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts new file mode 100644 index 00000000000000..1ce42c6d1ffd12 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { isOfAggregateQueryType } from '@kbn/es-query'; +import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; +import { isDataViewSource, isEsqlSource } from '../../../../common/data_sources'; +import { + DataSourceCategory, + DataSourceProfileProvider, + DataSourceProfileProviderParams, +} from '../../profiles'; +import { ProfileProviderServices } from '../../profiles/profile_provider_services'; + +export const createLogsDataSourceProfileProvider = ( + services: ProfileProviderServices +): DataSourceProfileProvider => ({ + profileId: 'logs-data-source-profile', + profile: {}, + resolve: (params) => { + const indexPattern = extractIndexPatternFrom(params); + + if (!services.logsContextService.isLogsIndexPattern(indexPattern)) { + return { isMatch: false }; + } + + return { + isMatch: true, + context: { category: DataSourceCategory.Logs }, + }; + }, +}); + +const extractIndexPatternFrom = ({ + dataSource, + dataView, + query, +}: DataSourceProfileProviderParams) => { + if (isEsqlSource(dataSource) && isOfAggregateQueryType(query)) { + return getIndexPatternFromESQLQuery(query.esql); + } else if (isDataViewSource(dataSource) && dataView) { + return dataView.getIndexPattern(); + } + + return null; +}; diff --git a/src/plugins/discover/public/context_awareness/profiles/profile_provider_services.ts b/src/plugins/discover/public/context_awareness/profiles/profile_provider_services.ts new file mode 100644 index 00000000000000..eced97659ecfad --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profiles/profile_provider_services.ts @@ -0,0 +1,27 @@ +/* + * 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 { createLogsContextService, LogsContextService } from '@kbn/discover-utils'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface ProfileProviderDeps { + // We will probably soon add uiSettings as a dependency + // to consume user configured indices +} + +export interface ProfileProviderServices { + logsContextService: LogsContextService; +} + +export const createProfileProviderServices = ( + _deps: ProfileProviderDeps = {} +): ProfileProviderServices => { + return { + logsContextService: createLogsContextService(), + }; +}; diff --git a/src/plugins/discover/public/index.ts b/src/plugins/discover/public/index.ts index a2ce384dd0e60b..bd88c4d6dbe094 100644 --- a/src/plugins/discover/public/index.ts +++ b/src/plugins/discover/public/index.ts @@ -9,7 +9,7 @@ import type { PluginInitializerContext } from '@kbn/core/public'; import { DiscoverPlugin } from './plugin'; -export type { DiscoverSetup, DiscoverStart } from './plugin'; +export type { DiscoverSetup, DiscoverStart } from './types'; export function plugin(initializerContext: PluginInitializerContext) { return new DiscoverPlugin(initializerContext); } diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index 7228070fe2d2c7..4f1ae2a32634e4 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { ComponentType } from 'react'; +import React from 'react'; import { BehaviorSubject, map, Observable } from 'rxjs'; import { AppMountParameters, @@ -17,42 +17,10 @@ import { PluginInitializerContext, ScopedHistory, } from '@kbn/core/public'; -import { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { ExpressionsSetup, ExpressionsStart } from '@kbn/expressions-plugin/public'; -import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; -import { ChartsPluginStart } from '@kbn/charts-plugin/public'; -import type { GlobalSearchPluginSetup } from '@kbn/global-search-plugin/public'; -import { NavigationPublicPluginStart as NavigationStart } from '@kbn/navigation-plugin/public'; -import { SharePluginStart, SharePluginSetup } from '@kbn/share-plugin/public'; -import { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; -import { HomePublicPluginSetup } from '@kbn/home-plugin/public'; -import { Start as InspectorPublicPluginStart } from '@kbn/inspector-plugin/public'; -import { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; import { ENABLE_ESQL } from '@kbn/esql-utils'; -import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; -import { IndexPatternFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public'; -import { DataViewsServicePublic } from '@kbn/data-views-plugin/public'; -import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; -import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; -import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; -import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; -import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; -import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; -import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; -import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; -import type { UnifiedDocViewerStart } from '@kbn/unified-doc-viewer-plugin/public'; import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; -import type { LensPublicStart } from '@kbn/lens-plugin/public'; import { TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; -import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; -import type { - ObservabilityAIAssistantPublicSetup, - ObservabilityAIAssistantPublicStart, -} from '@kbn/observability-ai-assistant-plugin/public'; -import type { AiopsPluginStart } from '@kbn/aiops-plugin/public'; -import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public'; import { PLUGIN_ID } from '../common'; import { registerFeature } from './register_feature'; import { buildServices, UrlTracker } from './build_services'; @@ -88,132 +56,10 @@ import { ProfilesManager, RootProfileService, } from './context_awareness'; - -/** - * @public - */ -export interface DiscoverSetup { - /** - * `share` plugin URL locator for Discover app. Use it to generate links into - * Discover application, for example, navigate: - * - * ```ts - * await plugins.discover.locator.navigate({ - * savedSearchId: '571aaf70-4c88-11e8-b3d7-01146121b73d', - * indexPatternId: 'c367b774-a4c2-11ea-bb37-0242ac130002', - * timeRange: { - * to: 'now', - * from: 'now-15m', - * mode: 'relative', - * }, - * }); - * ``` - * - * Generate a location: - * - * ```ts - * const location = await plugins.discover.locator.getLocation({ - * savedSearchId: '571aaf70-4c88-11e8-b3d7-01146121b73d', - * indexPatternId: 'c367b774-a4c2-11ea-bb37-0242ac130002', - * timeRange: { - * to: 'now', - * from: 'now-15m', - * mode: 'relative', - * }, - * }); - * ``` - */ - readonly locator: undefined | DiscoverAppLocator; - readonly showInlineTopNav: () => void; - readonly configureInlineTopNav: ( - projectNavId: string, - options: DiscoverCustomizationContext['inlineTopNav'] - ) => void; -} - -export interface DiscoverStart { - /** - * `share` plugin URL locator for Discover app. Use it to generate links into - * Discover application, for example, navigate: - * - * ```ts - * await plugins.discover.locator.navigate({ - * savedSearchId: '571aaf70-4c88-11e8-b3d7-01146121b73d', - * indexPatternId: 'c367b774-a4c2-11ea-bb37-0242ac130002', - * timeRange: { - * to: 'now', - * from: 'now-15m', - * mode: 'relative', - * }, - * }); - * ``` - * - * Generate a location: - * - * ```ts - * const location = await plugins.discover.locator.getLocation({ - * savedSearchId: '571aaf70-4c88-11e8-b3d7-01146121b73d', - * indexPatternId: 'c367b774-a4c2-11ea-bb37-0242ac130002', - * timeRange: { - * to: 'now', - * from: 'now-15m', - * mode: 'relative', - * }, - * }); - * ``` - */ - readonly locator: undefined | DiscoverAppLocator; - readonly DiscoverContainer: ComponentType; -} - -/** - * @internal - */ -export interface DiscoverSetupPlugins { - dataViews: DataViewsServicePublic; - share?: SharePluginSetup; - uiActions: UiActionsSetup; - embeddable: EmbeddableSetup; - urlForwarding: UrlForwardingSetup; - home?: HomePublicPluginSetup; - data: DataPublicPluginSetup; - expressions: ExpressionsSetup; - globalSearch?: GlobalSearchPluginSetup; - observabilityAIAssistant?: ObservabilityAIAssistantPublicSetup; -} - -/** - * @internal - */ -export interface DiscoverStartPlugins { - aiops?: AiopsPluginStart; - dataViews: DataViewsServicePublic; - dataViewEditor: DataViewEditorStart; - dataVisualizer?: DataVisualizerPluginStart; - uiActions: UiActionsStart; - embeddable: EmbeddableStart; - navigation: NavigationStart; - charts: ChartsPluginStart; - data: DataPublicPluginStart; - fieldFormats: FieldFormatsStart; - share?: SharePluginStart; - urlForwarding: UrlForwardingStart; - inspector: InspectorPublicPluginStart; - usageCollection?: UsageCollectionSetup; - dataViewFieldEditor: IndexPatternFieldEditorStart; - spaces?: SpacesPluginStart; - triggersActionsUi: TriggersAndActionsUIPublicPluginStart; - expressions: ExpressionsStart; - savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart; - savedObjectsManagement: SavedObjectsManagementPluginStart; - savedSearch: SavedSearchPublicPluginStart; - unifiedSearch: UnifiedSearchPublicPluginStart; - unifiedDocViewer: UnifiedDocViewerStart; - lens: LensPublicStart; - contentManagement: ContentManagementPublicStart; - noDataPage?: NoDataPagePluginStart; - observabilityAIAssistant?: ObservabilityAIAssistantPublicStart; -} +import { createProfileProviderServices } from './context_awareness/profiles/profile_provider_services'; +import { DiscoverSetup, DiscoverSetupPlugins, DiscoverStart, DiscoverStartPlugins } from './types'; +import { createLogsDataSourceProfileProvider } from './context_awareness/profile_providers/logs_data_source_profile'; +import { createLogDocumentProfileProvider } from './context_awareness/profile_providers/log_document_profile'; /** * Contains Discover, one of the oldest parts of Kibana @@ -459,10 +305,14 @@ export class DiscoverPlugin } private registerProfiles() { - // TODO: Conditionally register example profiles for functional testing in a follow up PR - // this.rootProfileService.registerProvider(o11yRootProfileProvider); - // this.dataSourceProfileService.registerProvider(logsDataSourceProfileProvider); - // this.documentProfileService.registerProvider(logDocumentProfileProvider); + const providerServices = createProfileProviderServices(); + + this.dataSourceProfileService.registerProvider( + createLogsDataSourceProfileProvider(providerServices) + ); + this.documentProfileService.registerProvider( + createLogDocumentProfileProvider(providerServices) + ); } private createProfilesManager() { diff --git a/src/plugins/discover/public/types.ts b/src/plugins/discover/public/types.ts new file mode 100644 index 00000000000000..54291a36a989b3 --- /dev/null +++ b/src/plugins/discover/public/types.ts @@ -0,0 +1,170 @@ +/* + * 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 { ComponentType } from 'react'; +import { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { ExpressionsSetup, ExpressionsStart } from '@kbn/expressions-plugin/public'; +import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; +import { ChartsPluginStart } from '@kbn/charts-plugin/public'; +import type { GlobalSearchPluginSetup } from '@kbn/global-search-plugin/public'; +import { NavigationPublicPluginStart as NavigationStart } from '@kbn/navigation-plugin/public'; +import { SharePluginStart, SharePluginSetup } from '@kbn/share-plugin/public'; +import { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; +import { HomePublicPluginSetup } from '@kbn/home-plugin/public'; +import { Start as InspectorPublicPluginStart } from '@kbn/inspector-plugin/public'; +import { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; +import { IndexPatternFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public'; +import { DataViewsServicePublic } from '@kbn/data-views-plugin/public'; +import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; +import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; +import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; +import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; +import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; +import type { UnifiedDocViewerStart } from '@kbn/unified-doc-viewer-plugin/public'; +import type { LensPublicStart } from '@kbn/lens-plugin/public'; +import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; +import type { + ObservabilityAIAssistantPublicSetup, + ObservabilityAIAssistantPublicStart, +} from '@kbn/observability-ai-assistant-plugin/public'; +import type { AiopsPluginStart } from '@kbn/aiops-plugin/public'; +import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public'; +import { DiscoverAppLocator } from '../common'; +import { DiscoverCustomizationContext } from './customizations'; +import { type DiscoverContainerProps } from './components/discover_container'; + +/** + * @public + */ +export interface DiscoverSetup { + /** + * `share` plugin URL locator for Discover app. Use it to generate links into + * Discover application, for example, navigate: + * + * ```ts + * await plugins.discover.locator.navigate({ + * savedSearchId: '571aaf70-4c88-11e8-b3d7-01146121b73d', + * indexPatternId: 'c367b774-a4c2-11ea-bb37-0242ac130002', + * timeRange: { + * to: 'now', + * from: 'now-15m', + * mode: 'relative', + * }, + * }); + * ``` + * + * Generate a location: + * + * ```ts + * const location = await plugins.discover.locator.getLocation({ + * savedSearchId: '571aaf70-4c88-11e8-b3d7-01146121b73d', + * indexPatternId: 'c367b774-a4c2-11ea-bb37-0242ac130002', + * timeRange: { + * to: 'now', + * from: 'now-15m', + * mode: 'relative', + * }, + * }); + * ``` + */ + readonly locator: undefined | DiscoverAppLocator; + readonly showInlineTopNav: () => void; + readonly configureInlineTopNav: ( + projectNavId: string, + options: DiscoverCustomizationContext['inlineTopNav'] + ) => void; +} + +export interface DiscoverStart { + /** + * `share` plugin URL locator for Discover app. Use it to generate links into + * Discover application, for example, navigate: + * + * ```ts + * await plugins.discover.locator.navigate({ + * savedSearchId: '571aaf70-4c88-11e8-b3d7-01146121b73d', + * indexPatternId: 'c367b774-a4c2-11ea-bb37-0242ac130002', + * timeRange: { + * to: 'now', + * from: 'now-15m', + * mode: 'relative', + * }, + * }); + * ``` + * + * Generate a location: + * + * ```ts + * const location = await plugins.discover.locator.getLocation({ + * savedSearchId: '571aaf70-4c88-11e8-b3d7-01146121b73d', + * indexPatternId: 'c367b774-a4c2-11ea-bb37-0242ac130002', + * timeRange: { + * to: 'now', + * from: 'now-15m', + * mode: 'relative', + * }, + * }); + * ``` + */ + readonly locator: undefined | DiscoverAppLocator; + readonly DiscoverContainer: ComponentType; +} + +/** + * @internal + */ +export interface DiscoverSetupPlugins { + data: DataPublicPluginSetup; + dataViews: DataViewsServicePublic; + embeddable: EmbeddableSetup; + expressions: ExpressionsSetup; + globalSearch?: GlobalSearchPluginSetup; + home?: HomePublicPluginSetup; + observabilityAIAssistant?: ObservabilityAIAssistantPublicSetup; + share?: SharePluginSetup; + uiActions: UiActionsSetup; + urlForwarding: UrlForwardingSetup; +} + +/** + * @internal + */ +export interface DiscoverStartPlugins { + aiops?: AiopsPluginStart; + charts: ChartsPluginStart; + contentManagement: ContentManagementPublicStart; + data: DataPublicPluginStart; + dataViewEditor: DataViewEditorStart; + dataViewFieldEditor: IndexPatternFieldEditorStart; + dataViews: DataViewsServicePublic; + dataVisualizer?: DataVisualizerPluginStart; + embeddable: EmbeddableStart; + expressions: ExpressionsStart; + fieldFormats: FieldFormatsStart; + inspector: InspectorPublicPluginStart; + lens: LensPublicStart; + navigation: NavigationStart; + noDataPage?: NoDataPagePluginStart; + observabilityAIAssistant?: ObservabilityAIAssistantPublicStart; + savedObjectsManagement: SavedObjectsManagementPluginStart; + savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart; + savedSearch: SavedSearchPublicPluginStart; + share?: SharePluginStart; + spaces?: SpacesPluginStart; + triggersActionsUi: TriggersAndActionsUIPublicPluginStart; + uiActions: UiActionsStart; + unifiedDocViewer: UnifiedDocViewerStart; + unifiedSearch: UnifiedSearchPublicPluginStart; + urlForwarding: UrlForwardingStart; + usageCollection?: UsageCollectionSetup; +} diff --git a/src/plugins/discover/public/utils/initialize_kbn_url_tracking.test.ts b/src/plugins/discover/public/utils/initialize_kbn_url_tracking.test.ts index e4a9a3edf6f641..999c75238739a2 100644 --- a/src/plugins/discover/public/utils/initialize_kbn_url_tracking.test.ts +++ b/src/plugins/discover/public/utils/initialize_kbn_url_tracking.test.ts @@ -8,7 +8,7 @@ import { AppUpdater } from '@kbn/core/public'; import { BehaviorSubject, Observable } from 'rxjs'; import { coreMock, scopedHistoryMock } from '@kbn/core/public/mocks'; -import { DiscoverSetupPlugins } from '../plugin'; +import { DiscoverSetupPlugins } from '../types'; import { initializeKbnUrlTracking } from './initialize_kbn_url_tracking'; describe('initializeKbnUrlTracking', () => { diff --git a/src/plugins/discover/public/utils/initialize_kbn_url_tracking.ts b/src/plugins/discover/public/utils/initialize_kbn_url_tracking.ts index 7ae8ac6d132ef9..8a4ed741acecf0 100644 --- a/src/plugins/discover/public/utils/initialize_kbn_url_tracking.ts +++ b/src/plugins/discover/public/utils/initialize_kbn_url_tracking.ts @@ -12,7 +12,7 @@ import { createKbnUrlTracker } from '@kbn/kibana-utils-plugin/public'; import { replaceUrlHashQuery } from '@kbn/kibana-utils-plugin/common'; import { isFilterPinned } from '@kbn/es-query'; import { SEARCH_SESSION_ID_QUERY_PARAM } from '../constants'; -import type { DiscoverSetupPlugins } from '../plugin'; +import type { DiscoverSetupPlugins } from '../types'; /** * It creates the kbn url tracker for Discover to listens to history changes and optionally to global state diff --git a/x-pack/plugins/observability_solution/apm/public/plugin.ts b/x-pack/plugins/observability_solution/apm/public/plugin.ts index 2f2f630cd43e70..82c05479c0520c 100644 --- a/x-pack/plugins/observability_solution/apm/public/plugin.ts +++ b/x-pack/plugins/observability_solution/apm/public/plugin.ts @@ -20,7 +20,7 @@ import { } from '@kbn/core/public'; import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import { DiscoverSetup, DiscoverStart } from '@kbn/discover-plugin/public/plugin'; +import { DiscoverSetup, DiscoverStart } from '@kbn/discover-plugin/public'; import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import type { ExploratoryViewPublicSetup } from '@kbn/exploratory-view-plugin/public'; import type { FeaturesPluginSetup } from '@kbn/features-plugin/public'; diff --git a/x-pack/plugins/observability_solution/logs_explorer/common/constants.ts b/x-pack/plugins/observability_solution/logs_explorer/common/constants.ts index ae8eff46fe7e2b..54ef1b50c587c9 100644 --- a/x-pack/plugins/observability_solution/logs_explorer/common/constants.ts +++ b/x-pack/plugins/observability_solution/logs_explorer/common/constants.ts @@ -59,6 +59,3 @@ export const FILTER_OUT_FIELDS_PREFIXES_FOR_CONTENT = [ 'log.', 'service.', ]; - -export const DEFAULT_ALLOWED_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat']; -export const DEFAULT_ALLOWED_LOGS_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat']; diff --git a/x-pack/plugins/observability_solution/logs_explorer/common/data_views/models/data_view_descriptor.ts b/x-pack/plugins/observability_solution/logs_explorer/common/data_views/models/data_view_descriptor.ts index 5b36b8e8bbe8b0..b5fe3d1f58c0f0 100644 --- a/x-pack/plugins/observability_solution/logs_explorer/common/data_views/models/data_view_descriptor.ts +++ b/x-pack/plugins/observability_solution/logs_explorer/common/data_views/models/data_view_descriptor.ts @@ -5,15 +5,13 @@ * 2.0. */ -import { DEFAULT_ALLOWED_LOGS_DATA_VIEWS } from '../../constants'; +import { createRegExpPatternFrom, testPatternAgainstAllowedList } from '@kbn/data-view-utils'; +import { DEFAULT_ALLOWED_LOGS_BASE_PATTERNS } from '@kbn/discover-utils'; import { DataViewSpecWithId } from '../../data_source_selection'; import { DataViewDescriptorType } from '../types'; -import { buildIndexPatternRegExp } from '../utils'; -type AllowedList = Array; - -const LOGS_ALLOWED_LIST: AllowedList = [ - buildIndexPatternRegExp(DEFAULT_ALLOWED_LOGS_DATA_VIEWS), +const LOGS_ALLOWED_LIST = [ + createRegExpPatternFrom(DEFAULT_ALLOWED_LOGS_BASE_PATTERNS), // Add more strings or regex patterns as needed ]; @@ -60,7 +58,9 @@ export class DataViewDescriptor { } testAgainstAllowedList(allowedList: string[]) { - return this.title ? isAllowed(this.title, [buildIndexPatternRegExp(allowedList)]) : false; + return this.title + ? testPatternAgainstAllowedList([createRegExpPatternFrom(allowedList)])(this.title) + : false; } public static create({ id, namespaces, title, type, name }: DataViewDescriptorFactoryParams) { @@ -79,7 +79,7 @@ export class DataViewDescriptor { } static #extractDataType(title: string): DataViewDescriptorType['dataType'] { - if (isAllowed(title, LOGS_ALLOWED_LIST)) { + if (testPatternAgainstAllowedList(LOGS_ALLOWED_LIST)(title)) { return 'logs'; } @@ -98,17 +98,3 @@ export class DataViewDescriptor { return this.dataType === 'unresolved'; } } - -function isAllowed(value: string, allowList: AllowedList) { - for (const allowedItem of allowList) { - if (typeof allowedItem === 'string') { - return value === allowedItem; - } - if (allowedItem instanceof RegExp) { - return allowedItem.test(value); - } - } - - // If no match is found in the allowList, return false - return false; -} diff --git a/x-pack/plugins/observability_solution/logs_explorer/common/ui_settings.ts b/x-pack/plugins/observability_solution/logs_explorer/common/ui_settings.ts index bbd3543d0dc69f..65983c39934889 100644 --- a/x-pack/plugins/observability_solution/logs_explorer/common/ui_settings.ts +++ b/x-pack/plugins/observability_solution/logs_explorer/common/ui_settings.ts @@ -7,9 +7,9 @@ import { schema } from '@kbn/config-schema'; import { UiSettingsParams } from '@kbn/core-ui-settings-common'; +import { DEFAULT_ALLOWED_LOGS_BASE_PATTERNS } from '@kbn/discover-utils'; import { i18n } from '@kbn/i18n'; import { OBSERVABILITY_LOGS_EXPLORER_ALLOWED_DATA_VIEWS_ID } from '@kbn/management-settings-ids'; -import { DEFAULT_ALLOWED_DATA_VIEWS } from './constants'; /** * uiSettings definitions for Logs Explorer. @@ -20,7 +20,7 @@ export const uiSettings: Record = { name: i18n.translate('xpack.logsExplorer.allowedDataViews', { defaultMessage: 'Logs Explorer allowed data views', }), - value: DEFAULT_ALLOWED_DATA_VIEWS, + value: DEFAULT_ALLOWED_LOGS_BASE_PATTERNS, description: i18n.translate('xpack.logsExplorer.allowedDataViewsDescription', { defaultMessage: 'A list of base patterns to match and explore data views in Logs Explorer. Remote clusters will be automatically matched for the provided base patterns.', diff --git a/x-pack/plugins/observability_solution/logs_explorer/tsconfig.json b/x-pack/plugins/observability_solution/logs_explorer/tsconfig.json index b30605fd567fde..b3f8c978a67b46 100644 --- a/x-pack/plugins/observability_solution/logs_explorer/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_explorer/tsconfig.json @@ -44,6 +44,7 @@ "@kbn/unified-search-plugin", "@kbn/xstate-utils", "@kbn/esql-utils", + "@kbn/data-view-utils", ], "exclude": [ "target/**/*" diff --git a/x-pack/test/functional/apps/observability_logs_explorer/data_source_selector.ts b/x-pack/test/functional/apps/observability_logs_explorer/data_source_selector.ts index 100d547cdb07dd..d4774b1ef66019 100644 --- a/x-pack/test/functional/apps/observability_logs_explorer/data_source_selector.ts +++ b/x-pack/test/functional/apps/observability_logs_explorer/data_source_selector.ts @@ -654,7 +654,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { PageObjects.observabilityLogsExplorer.getPanelEntries(menu) ); - expect(menuEntries.length).to.be(1); + expect(menuEntries.length).to.be(2); expect(await menuEntries[0].getVisibleText()).to.be(sortedExpectedDataViews[0]); }); From 014678003c30836faef3eb5e7222b1c0560d8c24 Mon Sep 17 00:00:00 2001 From: Jeramy Soucy Date: Tue, 18 Jun 2024 13:04:52 +0200 Subject: [PATCH 021/123] =?UTF-8?q?Upgrade=20@grpc/grpc-js@1.6.8=E2=86=921?= =?UTF-8?q?.8.22=20(#186067)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Upgrades the `@grpc/grpc-js` dependency from v1.6.8 to v1.8.22 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e8d694bb323e87..eaae0b675e62e3 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "@formatjs/intl-pluralrules": "^5.2.12", "@formatjs/intl-relativetimeformat": "^11.2.12", "@formatjs/intl-utils": "^3.8.4", - "@grpc/grpc-js": "^1.6.8", + "@grpc/grpc-js": "^1.8.22", "@hapi/accept": "^5.0.2", "@hapi/boom": "^9.1.4", "@hapi/cookie": "^11.0.2", diff --git a/yarn.lock b/yarn.lock index abf9faf49c8ae1..463d1d469c7b14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2490,10 +2490,10 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== -"@grpc/grpc-js@^1.6.8", "@grpc/grpc-js@^1.7.1": - version "1.8.17" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.17.tgz#a3a2f826fc033eae7d2f5ee41e0ab39cee948838" - integrity sha512-DGuSbtMFbaRsyffMf+VEkVu8HkSXEUfO3UyGJNtqxW9ABdtTIA+2UXAJpwbJS+xfQxuwqLUeELmL6FuZkOqPxw== +"@grpc/grpc-js@^1.7.1", "@grpc/grpc-js@^1.8.22": + version "1.8.22" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.22.tgz#847930c9af46e14df05b57fc12325db140ceff1d" + integrity sha512-oAjDdN7fzbUi+4hZjKG96MR6KTEubAeMpQEb+77qy+3r0Ua5xTFuie6JOLr4ZZgl5g+W5/uRTS2M1V8mVAFPuA== dependencies: "@grpc/proto-loader" "^0.7.0" "@types/node" ">=12.12.47" From 7528264531a806c6edda08c7a37c85ddbb05213f Mon Sep 17 00:00:00 2001 From: Bena Kansara <69037875+benakansara@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:14:37 +0200 Subject: [PATCH 022/123] [Observability] [Alert detail pages] Make common alert summary fields consistent for all pages with clickable source (#185933) Closes https://github.com/elastic/kibana/issues/183624 Closes https://github.com/elastic/kibana/issues/181692 Makes common alert summary fields consistent for all alert detail pages, with clickable links for source fields. Common alert summary fields: - Source - Tags - Rule Any additional fields specified in `AlertDetailsAppSection` would appear after these common fields. To make it consistent, I needed to do following small adjustments: - Changed "Source SLO" to "SLO" in burn rate alert - Changed "SLO Instance" to "Source" in burn rate alert - Moved "View related logs" to its separate label in custom threshold alert Additionally, following changes are made. - Added `kibana.alert.group` in Log threshold alert and SLO burn rate alert. - The "Affected source/entity" column in alert flyout matches the "Source" in alert details page. Before | After :---: | :---: Metric threshold alert Screenshot 2024-06-12 at
12 16 41 | Metric threshold alert Screenshot 2024-06-12 at
11 12 16 APM latency threshold alert Screenshot 2024-06-12
at 12 00 23 | APM latency threshold alert Screenshot
2024-06-12 at 11 11 23 Log threshold alert Screenshot 2024-06-12 at 12
17 42 | Log threshold alert Screenshot 2024-06-12 at 11
07 07 SLO burn rate alert Screenshot 2024-06-12 at 12
02 24 | SLO burn rate alert Screenshot 2024-06-12 at 11
12 56 Custom threshold alert Screenshot 2024-06-12 at
12 03 07 | Custom threshold alert Screenshot 2024-06-12 at
11 09 03 The "Affected source/entity" column in alert flyout matches the "Source" in alert details page. Before | After :---: | :---: Log threshold alert Screenshot 2024-06-12 at 12 11
28 | Log threshold alert Screenshot 2024-06-12 at 11
14 20 SLO burn rate alert Screenshot 2024-06-12 at 12 08
26 | SLO burn rate alert Screenshot 2024-06-12 at 11
14 44 Added `kibana.alert.group` in Log threshold alert and SLO burn rate alert. Log threshold alert Screenshot 2024-06-12 at 11 16 50 SLO burn rate alert Screenshot 2024-06-12 at 11 17 11 --- .../alert_details_app_section/index.tsx | 31 ------- .../common => common/alerting}/types.ts | 0 .../alert_details_app_section/index.tsx | 36 +------- .../alert_details_app_section/types.ts | 5 -- .../alert_details_app_section.test.tsx | 38 --------- .../components/alert_details_app_section.tsx | 54 +----------- .../metric_threshold/components/groups.tsx | 24 ------ .../infra/server/lib/alerting/common/utils.ts | 2 +- .../log_threshold/log_threshold_executor.ts | 18 +++- .../metric_threshold_executor.test.ts | 2 +- .../metric_threshold_executor.ts | 2 +- .../get_view_in_app_url.ts | 3 +- .../helpers/get_group.ts | 2 +- .../common/custom_threshold_rule/types.ts | 15 ---- .../observability/common/typings.ts | 13 +++ .../alert_overview/alert_overview.tsx | 4 +- .../alert_overview/overview_columns.tsx | 4 +- .../get_alert_source_links.test.ts | 0 .../alert_sources}/get_alert_source_links.ts | 4 +- .../alert_sources}/get_apm_app_url.ts | 0 .../helpers => alert_sources}/get_sources.ts | 13 +-- .../groups.tsx | 13 ++- .../alert_details_app_section.test.tsx | 67 +++------------ .../alert_details_app_section.tsx | 75 ++++------------- .../helpers/log_rate_analysis_query.ts | 6 +- .../alert_details_app_section/tags.tsx | 49 ----------- .../public}/components/tags.tsx | 4 +- .../pages/alert_details/alert_details.tsx | 3 +- .../components/alert_summary.test.tsx | 49 ++++++++++- .../components/alert_summary.tsx | 83 +++++++++++++++++-- .../components/header_actions.test.tsx | 30 +++---- .../public/pages/alert_details/mock/alert.ts | 13 ++- .../mock/alert_summary_fields.ts | 11 +-- .../custom_threshold_executor.ts | 2 +- .../lib/rules/custom_threshold/types.ts | 2 +- .../lib/rules/custom_threshold/utils.ts | 2 +- .../alert_details_app_section.tsx | 28 +------ .../lib/rules/slo_burn_rate/executor.test.ts | 48 +++++++++-- .../lib/rules/slo_burn_rate/executor.ts | 18 +++- .../server/lib/rules/slo_burn_rate/types.ts | 5 ++ .../translations/translations/fr-FR.json | 8 -- .../translations/translations/ja-JP.json | 8 -- .../translations/translations/zh-CN.json | 8 -- 43 files changed, 310 insertions(+), 492 deletions(-) rename x-pack/plugins/observability_solution/infra/{server/lib/alerting/common => common/alerting}/types.ts (100%) delete mode 100644 x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/groups.tsx rename x-pack/plugins/observability_solution/observability/{common/custom_threshold_rule/helpers => public/components/alert_sources}/get_alert_source_links.test.ts (100%) rename x-pack/plugins/observability_solution/observability/{common/custom_threshold_rule/helpers => public/components/alert_sources}/get_alert_source_links.ts (96%) rename x-pack/plugins/observability_solution/observability/{common/custom_threshold_rule => public/components/alert_sources}/get_apm_app_url.ts (100%) rename x-pack/plugins/observability_solution/observability/public/components/{alert_overview/helpers => alert_sources}/get_sources.ts (75%) rename x-pack/plugins/observability_solution/observability/public/components/{custom_threshold/components/alert_details_app_section => alert_sources}/groups.tsx (76%) delete mode 100644 x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/tags.tsx rename x-pack/plugins/observability_solution/{infra/public/alerting/metric_threshold => observability/public}/components/tags.tsx (89%) diff --git a/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/index.tsx index 7bea5746e461f1..b9a7f4e8d82544 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/index.tsx @@ -74,37 +74,6 @@ export function AlertDetailsAppSection({ ), value: formatAlertEvaluationValue(alertRuleTypeId, alertEvaluationThreshold), }, - { - label: ( - - ), - value: environment, - }, - { - label: ( - - ), - value: serviceName, - }, - ...(transactionName - ? [ - { - label: ( - - ), - value: transactionName, - }, - ] - : []), ]; setAlertSummaryFields(alertSummaryFields); }, [ diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/common/types.ts b/x-pack/plugins/observability_solution/infra/common/alerting/types.ts similarity index 100% rename from x-pack/plugins/observability_solution/infra/server/lib/alerting/common/types.ts rename to x-pack/plugins/observability_solution/infra/common/alerting/types.ts diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx b/x-pack/plugins/observability_solution/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx index ae0021adb2e01b..36e2e91af9db0f 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx +++ b/x-pack/plugins/observability_solution/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { LEGACY_LIGHT_THEME } from '@elastic/charts'; import { EuiPanel } from '@elastic/eui'; @@ -37,16 +37,11 @@ import { useLicense } from '../../../../hooks/use_license'; const formatThreshold = (threshold: number) => String(threshold); -const AlertDetailsAppSection = ({ - rule, - alert, - setAlertSummaryFields, -}: AlertDetailsAppSectionProps) => { +const AlertDetailsAppSection = ({ rule, alert }: AlertDetailsAppSectionProps) => { const { logsShared } = useKibanaContextForPlugin().services; const theme = useTheme(); const timeRange = getPaddedAlertTimeRange(alert.fields[ALERT_START]!, alert.fields[ALERT_END]); const alertEnd = alert.fields[ALERT_END] ? moment(alert.fields[ALERT_END]).valueOf() : undefined; - const alertContext = alert.fields[ALERT_CONTEXT]; const interval = `${rule.params.timeSize}${rule.params.timeUnit}`; const thresholdFill = convertComparatorToFill(rule.params.count.comparator); const filter = rule.params.groupBy @@ -71,33 +66,6 @@ const AlertDetailsAppSection = ({ const { hasAtLeast } = useLicense(); const hasLicenseForLogRateAnalysis = hasAtLeast('platinum'); - useEffect(() => { - /** - * The `CriterionPreview` chart shows all the series/data stacked when there is a GroupBy in the rule parameters. - * e.g., `host.name`, the chart will show stacks of data by hostname. - * We only need the chart to show the series that is related to the selected alert. - * The chart series are built based on the GroupBy in the rule params - * Each series have an id which is the just a joining of fields value of the GroupBy `getChartGroupNames` - * We filter down the series using this group name - */ - const alertFieldsFromGroupBy = - rule.params.groupBy?.reduce( - (selectedFields: Record, field) => ({ - ...selectedFields, - ...{ - [field]: get(alertContext, ['groupByKeys', ...field.split('.')], null), - }, - }), - {} - ) || {}; - - const alertSummaryFields = Object.entries(alertFieldsFromGroupBy).map(([label, value]) => ({ - label, - value, - })); - setAlertSummaryFields(alertSummaryFields); - }, [alertContext, rule.params.groupBy, setAlertSummaryFields]); - const getLogRatioChart = () => { if (isRatioRule(rule.params.criteria)) { const numeratorKql = rule.params.criteria[0] diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/log_threshold/components/alert_details_app_section/types.ts b/x-pack/plugins/observability_solution/infra/public/alerting/log_threshold/components/alert_details_app_section/types.ts index ee89bc3baea634..c76778aa81251a 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/log_threshold/components/alert_details_app_section/types.ts +++ b/x-pack/plugins/observability_solution/infra/public/alerting/log_threshold/components/alert_details_app_section/types.ts @@ -14,8 +14,3 @@ export interface AlertDetailsAppSectionProps { alert: TopAlert>; setAlertSummaryFields: React.Dispatch>; } - -export interface Group { - field: string; - value: string; -} diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx index f7827fcbcadbbe..eaf077684cf4da 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx +++ b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import { EuiLink } from '@elastic/eui'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { coreMock as mockCoreMock } from '@kbn/core/public/mocks'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; @@ -18,8 +17,6 @@ import { } from '../mocks/metric_threshold_rule'; import { AlertDetailsAppSection } from './alert_details_app_section'; import { ExpressionChart } from './expression_chart'; -import { Groups } from './groups'; -import { Tags } from './tags'; const mockedChartStartContract = chartPluginMock.createStartContract(); @@ -51,7 +48,6 @@ jest.mock('../../../hooks/use_kibana', () => ({ describe('AlertDetailsAppSection', () => { const queryClient = new QueryClient(); const mockedSetAlertSummaryFields = jest.fn(); - const ruleLink = 'ruleLink'; const renderComponent = () => { return render( @@ -59,7 +55,6 @@ describe('AlertDetailsAppSection', () => { @@ -78,39 +73,6 @@ describe('AlertDetailsAppSection', () => { expect(result.getByTestId('threshold-2000-2500')).toBeTruthy(); }); - it('should render alert summary fields', async () => { - renderComponent(); - - expect(mockedSetAlertSummaryFields).toBeCalledTimes(1); - expect(mockedSetAlertSummaryFields).toBeCalledWith([ - { - label: 'Source', - value: ( - - ), - }, - { - label: 'Tags', - value: , - }, - { - label: 'Rule', - value: ( - - Monitoring hosts - - ), - }, - ]); - }); - it('should render annotations', async () => { const mockedExpressionChart = jest.fn(() =>
); (ExpressionChart as jest.Mock).mockImplementation(mockedExpressionChart); diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx index 6a9e4999714bc8..bee0035f210c1e 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx +++ b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx @@ -7,25 +7,18 @@ import { i18n } from '@kbn/i18n'; import { convertToBuiltInComparators } from '@kbn/observability-plugin/common'; -import React, { useEffect } from 'react'; +import React from 'react'; import moment from 'moment'; import { EuiFlexGroup, EuiFlexItem, - EuiLink, EuiPanel, EuiSpacer, EuiTitle, useEuiTheme, } from '@elastic/eui'; import { AlertSummaryField, TopAlert } from '@kbn/observability-plugin/public'; -import { - ALERT_END, - ALERT_START, - ALERT_EVALUATION_VALUES, - ALERT_GROUP, - TAGS, -} from '@kbn/rule-data-utils'; +import { ALERT_END, ALERT_START, ALERT_EVALUATION_VALUES, ALERT_GROUP } from '@kbn/rule-data-utils'; import { Rule } from '@kbn/alerting-plugin/common'; import { AlertAnnotation, AlertActiveTimeRangeAnnotation } from '@kbn/observability-alert-details'; import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; @@ -37,8 +30,6 @@ import { MetricsExplorerChartType } from '../../../pages/metrics/metrics_explore import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { MetricThresholdRuleTypeParams } from '..'; import { ExpressionChart } from './expression_chart'; -import { Groups } from './groups'; -import { Tags } from './tags'; // TODO Use a generic props for app sections https://github.com/elastic/kibana/issues/152690 export type MetricThresholdRule = Rule< @@ -67,21 +58,13 @@ const ALERT_TIME_RANGE_ANNOTATION_ID = 'alert_time_range_annotation'; interface AppSectionProps { alert: MetricThresholdAlert; rule: MetricThresholdRule; - ruleLink: string; setAlertSummaryFields: React.Dispatch>; } -export function AlertDetailsAppSection({ - alert, - rule, - ruleLink, - setAlertSummaryFields, -}: AppSectionProps) { +export function AlertDetailsAppSection({ alert, rule }: AppSectionProps) { const { uiSettings, charts } = useKibanaContextForPlugin().services; const { euiTheme } = useEuiTheme(); const groupInstance = alert.fields[ALERT_GROUP]?.map((group: Group) => group.value); - const groups = alert.fields[ALERT_GROUP]; - const tags = alert.fields[TAGS]; const chartProps = { baseTheme: charts.theme.useChartsBaseTheme(), @@ -103,37 +86,6 @@ export function AlertDetailsAppSection({ key={ALERT_TIME_RANGE_ANNOTATION_ID} />, ]; - useEffect(() => { - const alertSummaryFields = []; - if (groups) { - alertSummaryFields.push({ - label: i18n.translate('xpack.infra.metrics.alertDetailsAppSection.summaryField.source', { - defaultMessage: 'Source', - }), - value: , - }); - } - if (tags && tags.length > 0) { - alertSummaryFields.push({ - label: i18n.translate('xpack.infra.metrics.alertDetailsAppSection.summaryField.tags', { - defaultMessage: 'Tags', - }), - value: , - }); - } - alertSummaryFields.push({ - label: i18n.translate('xpack.infra.metrics.alertDetailsAppSection.summaryField.rule', { - defaultMessage: 'Rule', - }), - value: ( - - {rule.name} - - ), - }); - - setAlertSummaryFields(alertSummaryFields); - }, [groups, tags, rule, ruleLink, setAlertSummaryFields]); return !!rule.params.criteria ? ( diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/groups.tsx b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/groups.tsx deleted file mode 100644 index c68fa2a391448e..00000000000000 --- a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/groups.tsx +++ /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 React from 'react'; - -export function Groups({ groups }: { groups: Array<{ field: string; value: string }> }) { - return ( - <> - {groups && - groups.map((group) => { - return ( - - {group.field}: {group.value} -
-
- ); - })} - - ); -} diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/common/utils.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/common/utils.ts index 9c506d215355a2..edfb50df0a788f 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/common/utils.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/common/utils.ts @@ -28,7 +28,7 @@ import { AlertExecutionDetails, InventoryMetricConditions, } from '../../../../common/alerting/metrics/types'; -import { Group } from './types'; +import { Group } from '../../../../common/alerting/types'; const ALERT_CONTEXT_CONTAINER = 'container'; const ALERT_CONTEXT_ORCHESTRATOR = 'orchestrator'; diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts index 01eed0023dda86..68eea51669e874 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts @@ -12,6 +12,7 @@ import { ALERT_CONTEXT, ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_VALUE, + ALERT_GROUP, ALERT_REASON, } from '@kbn/rule-data-utils'; import { ElasticsearchClient, IBasePath } from '@kbn/core/server'; @@ -76,15 +77,20 @@ import { LogThresholdRuleTypeParams, positiveComparators, } from '../../../../common/alerting/logs/log_threshold/query_helpers'; +import { Group } from '../../../../common/alerting/types'; export type LogThresholdActionGroups = ActionGroupIdsOf; export type LogThresholdRuleTypeState = RuleTypeState; // no specific state used export type LogThresholdAlertState = AlertState; // no specific state used export type LogThresholdAlertContext = AlertContext; // no specific instance context used -export type LogThresholdAlert = Omit & { +export type LogThresholdAlert = Omit< + ObservabilityLogsAlert, + 'kibana.alert.evaluation.values' | 'kibana.alert.group' +> & { // Defining a custom type for this because the schema generation script doesn't allow explicit null values 'kibana.alert.evaluation.values'?: Array; + [ALERT_GROUP]?: Group[]; }; export type LogThresholdAlertReporter = ( @@ -169,11 +175,21 @@ export const createLogThresholdExecutor = alertDetailsUrl: getAlertDetailsUrl(libs.basePath, spaceId, uuid), }; + const instances = alertInstanceId.split(','); + const groups = + alertInstanceId !== '*' + ? params.groupBy?.reduce((resultGroups, groupByItem, index) => { + resultGroups.push({ field: groupByItem, value: instances[index].trim() }); + return resultGroups; + }, []) + : undefined; + const payload = { [ALERT_EVALUATION_THRESHOLD]: threshold, [ALERT_EVALUATION_VALUE]: value, [ALERT_REASON]: reason, [ALERT_CONTEXT]: alertContext, + [ALERT_GROUP]: groups, ...flattenAdditionalContext(rootLevelContext), }; diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 9cc5712ce09b60..d95a24478a6ff9 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -30,7 +30,7 @@ import { ALERT_REASON, ALERT_GROUP, } from '@kbn/rule-data-utils'; -import { Group } from '../common/types'; +import { Group } from '../../../../common/alerting/types'; jest.mock('./lib/evaluate_rule', () => ({ evaluateRule: jest.fn() })); diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts index 49129e2058cc18..f05c98d6cc2221 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts @@ -48,11 +48,11 @@ import { getFormattedGroupBy, } from '../common/utils'; import { getEvaluationValues, getThresholds } from '../common/get_values'; -import { Group } from '../common/types'; import { EvaluatedRuleParams, evaluateRule, Evaluation } from './lib/evaluate_rule'; import { MissingGroupsRecord } from './lib/check_missing_group'; import { convertStringsToMissingGroupsRecord } from './lib/convert_strings_to_missing_groups_record'; +import { Group } from '../../../../common/alerting/types'; export type MetricThresholdAlert = Omit< ObservabilityMetricsAlert, diff --git a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/get_view_in_app_url.ts b/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/get_view_in_app_url.ts index 9715b8b5f9c861..5411eff43bc3d3 100644 --- a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/get_view_in_app_url.ts +++ b/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/get_view_in_app_url.ts @@ -10,8 +10,9 @@ import type { TimeRange } from '@kbn/es-query'; import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; import type { LocatorPublic } from '@kbn/share-plugin/common'; import { getGroupFilters } from './helpers/get_group'; -import { Group, SearchConfigurationWithExtractedReferenceType } from './types'; +import { SearchConfigurationWithExtractedReferenceType } from './types'; import type { CustomThresholdExpressionMetric } from './types'; +import { Group } from '../typings'; export interface GetViewInAppUrlArgs { searchConfiguration?: SearchConfigurationWithExtractedReferenceType; diff --git a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/helpers/get_group.ts b/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/helpers/get_group.ts index 3194fc4e14b2db..67437421e4bad3 100644 --- a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/helpers/get_group.ts +++ b/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/helpers/get_group.ts @@ -7,7 +7,7 @@ import { Filter } from '@kbn/es-query'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { Group } from '../types'; +import { Group } from '../../typings'; /* * groupFieldName diff --git a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/types.ts b/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/types.ts index 0e4a0e71670698..c2a616682cfdb2 100644 --- a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/types.ts +++ b/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/types.ts @@ -106,16 +106,6 @@ export enum InfraFormatterType { percent = 'percent', } -export interface Group { - field: string; - value: string; -} - -export interface TimeRange { - from?: string; - to?: string; -} - export interface SearchConfigurationType { index: SerializedSearchSourceFields; query: { @@ -135,11 +125,6 @@ export interface SearchConfigurationWithExtractedReferenceType { filter?: Filter[]; } -// Custom threshold alert types - -// Alert fields['kibana.alert.group] type -export type GroupBy = Group[]; - /* * Utils * diff --git a/x-pack/plugins/observability_solution/observability/common/typings.ts b/x-pack/plugins/observability_solution/observability/common/typings.ts index dfddf89992c19b..bfdcd6d5209dc0 100644 --- a/x-pack/plugins/observability_solution/observability/common/typings.ts +++ b/x-pack/plugins/observability_solution/observability/common/typings.ts @@ -41,3 +41,16 @@ export interface AlertStatusFilter { query: string; label: string; } + +export interface Group { + field: string; + value: string; +} + +export interface TimeRange { + from?: string; + to?: string; +} + +// Alert fields['kibana.alert.group] type +export type GroupBy = Group[]; diff --git a/x-pack/plugins/observability_solution/observability/public/components/alert_overview/alert_overview.tsx b/x-pack/plugins/observability_solution/observability/public/components/alert_overview/alert_overview.tsx index 95e043dd3da1c9..57a34d7fdf1f9c 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alert_overview/alert_overview.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/alert_overview/alert_overview.tsx @@ -34,7 +34,6 @@ import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-tim import { get } from 'lodash'; import { paths } from '../../../common/locators/paths'; -import { TimeRange } from '../../../common/custom_threshold_rule/types'; import { TopAlert } from '../../typings/alerts'; import { useFetchBulkCases } from '../../hooks/use_fetch_bulk_cases'; import { useCaseViewNavigation } from '../../hooks/use_case_view_navigation'; @@ -44,8 +43,9 @@ import { mapRuleParamsWithFlyout, } from './helpers/map_rules_params_with_flyout'; import { ColumnIDs, overviewColumns } from './overview_columns'; -import { getSources } from './helpers/get_sources'; +import { getSources } from '../alert_sources/get_sources'; import { RULE_DETAILS_PAGE_ID } from '../../pages/rule_details/constants'; +import { TimeRange } from '../../../common/typings'; export const AlertOverview = memo( ({ diff --git a/x-pack/plugins/observability_solution/observability/public/components/alert_overview/overview_columns.tsx b/x-pack/plugins/observability_solution/observability/public/components/alert_overview/overview_columns.tsx index a1581333294ea8..d2c3eb58854eec 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alert_overview/overview_columns.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/alert_overview/overview_columns.tsx @@ -15,11 +15,11 @@ import React from 'react'; import { Tooltip as CaseTooltip } from '@kbn/cases-components'; import { COMPARATORS } from '@kbn/alerting-comparators'; import { LEGACY_COMPARATORS } from '../../../common/utils/convert_legacy_outside_comparator'; -import type { Group } from '../../../common/custom_threshold_rule/types'; import { NavigateToCaseView } from '../../hooks/use_case_view_navigation'; -import { Groups } from '../custom_threshold/components/alert_details_app_section/groups'; import { formatCase } from './helpers/format_cases'; import { FlyoutThresholdData } from './helpers/map_rules_params_with_flyout'; +import { Groups } from '../alert_sources/groups'; +import type { Group } from '../../../common/typings'; interface AlertOverviewField { id: string; diff --git a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/helpers/get_alert_source_links.test.ts b/x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_alert_source_links.test.ts similarity index 100% rename from x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/helpers/get_alert_source_links.test.ts rename to x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_alert_source_links.test.ts diff --git a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/helpers/get_alert_source_links.ts b/x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_alert_source_links.ts similarity index 96% rename from x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/helpers/get_alert_source_links.ts rename to x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_alert_source_links.ts index 0595d7554fb0b2..ff1d39d85b1d4b 100644 --- a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/helpers/get_alert_source_links.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_alert_source_links.ts @@ -13,8 +13,8 @@ import { } from '@kbn/observability-shared-plugin/common'; import { LocatorPublic } from '@kbn/share-plugin/common'; import { SerializableRecord } from '@kbn/utility-types'; -import { getApmAppLocator } from '../get_apm_app_url'; -import { Group, TimeRange } from '../types'; +import { getApmAppLocator } from './get_apm_app_url'; +import { Group, TimeRange } from '../../../common/typings'; const HOST_NAME = 'host.name'; const CONTAINER_ID = 'container.id'; diff --git a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/get_apm_app_url.ts b/x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_apm_app_url.ts similarity index 100% rename from x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/get_apm_app_url.ts rename to x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_apm_app_url.ts diff --git a/x-pack/plugins/observability_solution/observability/public/components/alert_overview/helpers/get_sources.ts b/x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_sources.ts similarity index 75% rename from x-pack/plugins/observability_solution/observability/public/components/alert_overview/helpers/get_sources.ts rename to x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_sources.ts index cfc64d9d414aa3..3832e744a31e62 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alert_overview/helpers/get_sources.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/alert_sources/get_sources.ts @@ -5,18 +5,19 @@ * 2.0. */ -import { ALERT_GROUP_FIELD, ALERT_GROUP_VALUE } from '@kbn/rule-data-utils'; -import { - apmSources, - infraSources, -} from '../../../../common/custom_threshold_rule/helpers/get_alert_source_links'; -import { TopAlert } from '../../..'; +import { ALERT_GROUP_FIELD, ALERT_GROUP_VALUE, ALERT_GROUP } from '@kbn/rule-data-utils'; +import { TopAlert } from '../../typings/alerts'; +import { apmSources, infraSources } from './get_alert_source_links'; interface AlertFields { [key: string]: any; } export const getSources = (alert: TopAlert) => { + // when `kibana.alert.group` is not flattened (for alert detail pages) + if (alert.fields[ALERT_GROUP]) return alert.fields[ALERT_GROUP]; + + // when `kibana.alert.group` is flattened (for alert flyout) const groupsFromGroupFields = alert.fields[ALERT_GROUP_FIELD]?.map((field, index) => { const values = alert.fields[ALERT_GROUP_VALUE]; if (values?.length && values[index]) { diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/groups.tsx b/x-pack/plugins/observability_solution/observability/public/components/alert_sources/groups.tsx similarity index 76% rename from x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/groups.tsx rename to x-pack/plugins/observability_solution/observability/public/components/alert_sources/groups.tsx index f2644ac78b0c57..5a14f39a97811f 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/groups.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/alert_sources/groups.tsx @@ -8,10 +8,10 @@ import { EuiLink } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; import { SERVICE_NAME } from '@kbn/observability-shared-plugin/common'; -import { useKibana } from '../../../../utils/kibana_react'; -import { TimeRange, Group } from '../../../../../common/custom_threshold_rule/types'; -import { generateSourceLink } from '../../../../../common/custom_threshold_rule/helpers/get_alert_source_links'; -import { APM_APP_LOCATOR_ID } from '../../../../../common/custom_threshold_rule/get_apm_app_url'; +import { useKibana } from '../../utils/kibana_react'; +import { APM_APP_LOCATOR_ID } from './get_apm_app_url'; +import { Group, TimeRange } from '../../../common/typings'; +import { generateSourceLink } from './get_alert_source_links'; export function Groups({ groups, timeRange }: { groups: Group[]; timeRange: TimeRange }) { const { @@ -57,10 +57,7 @@ export function Groups({ groups, timeRange }: { groups: Group[]; timeRange: Time {group.field}:{' '} {sourceLinks[group.field] ? ( - + {group.value} ) : ( diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx index a30511c891e7ba..35104fd199d3ab 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx @@ -21,8 +21,6 @@ import { CustomThresholdAlertFields } from '../../types'; import { RuleConditionChart } from '../rule_condition_chart/rule_condition_chart'; import { CustomThresholdAlert } from '../types'; import AlertDetailsAppSection from './alert_details_app_section'; -import { Groups } from './groups'; -import { Tags } from './tags'; const mockedChartStartContract = chartPluginMock.createStartContract(); @@ -80,7 +78,6 @@ jest.mock('../../../../utils/kibana_react', () => ({ describe('AlertDetailsAppSection', () => { const queryClient = new QueryClient(); const mockedSetAlertSummaryFields = jest.fn(); - const ruleLink = 'ruleLink'; const renderComponent = ( alert: Partial = {}, @@ -92,7 +89,6 @@ describe('AlertDetailsAppSection', () => { @@ -111,65 +107,22 @@ describe('AlertDetailsAppSection', () => { expect(result.getByTestId('thresholdRule-2000-2500')).toBeTruthy(); }); - it('should render alert summary fields', async () => { + it('should render additional alert summary fields', async () => { renderComponent(); expect(mockedSetAlertSummaryFields).toBeCalledTimes(2); expect(mockedSetAlertSummaryFields).toBeCalledWith([ { - label: 'Source', + label: 'Related logs', value: ( - - - - - View related logs - - - - ), - }, - { - label: 'Tags', - value: , - }, - { - label: 'Rule', - value: ( - - Monitoring hosts - - ), - }, - ]); - }); - - it('should not render group and tag summary fields', async () => { - const alertFields = { tags: [], 'kibana.alert.group': undefined }; - renderComponent({}, alertFields); - - expect(mockedSetAlertSummaryFields).toBeCalledTimes(2); - expect(mockedSetAlertSummaryFields).toBeCalledWith([ - { - label: 'Rule', - value: ( - - Monitoring hosts - + + + View related logs + + ), }, ]); diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx index c0c399914acd9a..3a065d6e06f3e6 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx @@ -21,13 +21,7 @@ import { } from '@elastic/eui'; import { RuleTypeParams } from '@kbn/alerting-plugin/common'; import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; -import { - ALERT_END, - ALERT_START, - ALERT_EVALUATION_VALUES, - ALERT_GROUP, - TAGS, -} from '@kbn/rule-data-utils'; +import { ALERT_END, ALERT_START, ALERT_EVALUATION_VALUES, ALERT_GROUP } from '@kbn/rule-data-utils'; import { DataView } from '@kbn/data-views-plugin/common'; import type { EventAnnotationConfig, @@ -46,8 +40,6 @@ import { AlertParams } from '../../types'; import { Threshold } from '../custom_threshold'; import { CustomThresholdRule, CustomThresholdAlert } from '../types'; import { LogRateAnalysis } from './log_rate_analysis'; -import { Groups } from './groups'; -import { Tags } from './tags'; import { RuleConditionChart } from '../rule_condition_chart/rule_condition_chart'; import { getViewInAppUrl } from '../../../../../common/custom_threshold_rule/get_view_in_app_url'; import { SearchConfigurationWithExtractedReferenceType } from '../../../../../common/custom_threshold_rule/types'; @@ -56,7 +48,6 @@ import { generateChartTitleAndTooltip } from './helpers/generate_chart_title_and interface AppSectionProps { alert: CustomThresholdAlert; rule: CustomThresholdRule; - ruleLink: string; setAlertSummaryFields: React.Dispatch>; } @@ -64,7 +55,6 @@ interface AppSectionProps { export default function AlertDetailsAppSection({ alert, rule, - ruleLink, setAlertSummaryFields, }: AppSectionProps) { const services = useKibana().services; @@ -89,7 +79,6 @@ export default function AlertDetailsAppSection({ const alertStart = alert.fields[ALERT_START]; const alertEnd = alert.fields[ALERT_END]; const groups = alert.fields[ALERT_GROUP]; - const tags = alert.fields[TAGS]; const chartTitleAndTooltip: Array<{ title: string; tooltip: string }> = []; @@ -145,64 +134,30 @@ export default function AlertDetailsAppSection({ useEffect(() => { const alertSummaryFields = []; - if (groups) { - alertSummaryFields.push({ - label: i18n.translate( - 'xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.source', - { - defaultMessage: 'Source', - } - ), - value: ( - <> - - - - {i18n.translate( - 'xpack.observability.alertDetailsAppSection.a.viewRelatedLogsLabel', - { - defaultMessage: 'View related logs', - } - )} - - - - ), - }); - } - if (tags && tags.length > 0) { - alertSummaryFields.push({ - label: i18n.translate( - 'xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.tags', - { - defaultMessage: 'Tags', - } - ), - value: , - }); - } + alertSummaryFields.push({ label: i18n.translate( - 'xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.rule', + 'xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.relatedLogs', { - defaultMessage: 'Rule', + defaultMessage: 'Related logs', } ), value: ( - - {rule.name} - + + + {i18n.translate('xpack.observability.alertDetailsAppSection.a.viewRelatedLogsLabel', { + defaultMessage: 'View related logs', + })} + + ), }); setAlertSummaryFields(alertSummaryFields); - }, [groups, tags, rule, ruleLink, setAlertSummaryFields, timeRange, alertEnd, viewInAppUrl]); + }, [viewInAppUrl, setAlertSummaryFields]); useEffect(() => { const initDataView = async () => { diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.ts b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.ts index 2eb3186a46a9d7..a23105f08cebf8 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/helpers/log_rate_analysis_query.ts @@ -10,12 +10,10 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { getGroupFilters } from '../../../../../../common/custom_threshold_rule/helpers/get_group'; import { Aggregators } from '../../../../../../common/custom_threshold_rule/types'; import { buildEsQuery } from '../../../../../utils/build_es_query'; -import type { - CustomThresholdExpressionMetric, - Group, -} from '../../../../../../common/custom_threshold_rule/types'; +import type { CustomThresholdExpressionMetric } from '../../../../../../common/custom_threshold_rule/types'; import type { TopAlert } from '../../../../../typings/alerts'; import type { CustomThresholdRuleTypeParams } from '../../../types'; +import { Group } from '../../../../../../common/typings'; const getKuery = (metrics: CustomThresholdExpressionMetric[], filter?: string) => { let query = ''; diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/tags.tsx b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/tags.tsx deleted file mode 100644 index b04d104695de86..00000000000000 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/tags.tsx +++ /dev/null @@ -1,49 +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 { i18n } from '@kbn/i18n'; -import React, { useState } from 'react'; -import { EuiBadge, EuiPopover } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; - -export function Tags({ tags }: { tags: string[] }) { - const [isMoreTagsOpen, setIsMoreTagsOpen] = useState(false); - const onMoreTagsClick = () => setIsMoreTagsOpen((isPopoverOpen) => !isPopoverOpen); - const closePopover = () => setIsMoreTagsOpen(false); - const moreTags = tags.length > 3 && ( - - - - ); - - return ( - <> - {tags.slice(0, 3).map((tag) => ( - {tag} - ))} -
- - {tags.slice(3).map((tag) => ( - {tag} - ))} - - - ); -} diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/tags.tsx b/x-pack/plugins/observability_solution/observability/public/components/tags.tsx similarity index 89% rename from x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/tags.tsx rename to x-pack/plugins/observability_solution/observability/public/components/tags.tsx index 6d5cb11a63b673..e7059463ef7bd7 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/tags.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/tags.tsx @@ -19,14 +19,14 @@ export function Tags({ tags }: { tags: string[] }) { key="more" onClick={onMoreTagsClick} onClickAriaLabel={i18n.translate( - 'xpack.infra.metrics.alertDetailsAppSection.summaryField.moreTags.ariaLabel', + 'xpack.observability.alertDetails.alertSummaryField.moreTags.ariaLabel', { defaultMessage: 'more tags badge', } )} > diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/alert_details.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/alert_details.tsx index e2bbfe4edda9aa..e17fc1666e0610 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/alert_details.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/alert_details.tsx @@ -174,7 +174,7 @@ export function AlertDetails() { isAlertDetailsEnabledPerApp(alertDetail.formatted, config) ? ( <> - + {rule && alertDetail.formatted && ( @@ -184,7 +184,6 @@ export function AlertDetails() { rule={rule} timeZone={timeZone} setAlertSummaryFields={setSummaryFields} - ruleLink={http.basePath.prepend(paths.observability.ruleDetails(rule.id))} /> ({ ...jest.requireActual('react-router-dom'), @@ -19,6 +29,21 @@ jest.mock('react-router-dom', () => ({ jest.mock('../../../utils/kibana_react'); +const useKibanaMock = useKibana as jest.Mock; + +const mockKibana = () => { + useKibanaMock.mockReturnValue({ + services: { + ...kibanaStartMock.startContract().services, + http: { + basePath: { + prepend: jest.fn(), + }, + }, + }, + }); +}; + describe('Alert summary', () => { jest .spyOn(useUiSettingHook, 'useUiSetting') @@ -26,14 +51,30 @@ describe('Alert summary', () => { beforeEach(() => { jest.clearAllMocks(); + mockKibana(); }); it('should show alert data', async () => { - const alertSummary = render(); + const alertSummary = render( + + ); + + const groups = alertWithGroupsAndTags.fields[ALERT_GROUP] as Group[]; + expect(alertSummary.queryByText('Source')).toBeInTheDocument(); + expect(alertSummary.queryByText(groups[0].field, { exact: false })).toBeInTheDocument(); + expect(alertSummary.queryByText(groups[0].value)).toBeInTheDocument(); + expect(alertSummary.queryByText(groups[1].field, { exact: false })).toBeInTheDocument(); + expect(alertSummary.queryByText(groups[1].value)).toBeInTheDocument(); + expect(alertSummary.queryByText('Tags')).toBeInTheDocument(); + expect(alertSummary.queryByText(alertWithGroupsAndTags.fields[TAGS]![0])).toBeInTheDocument(); + expect(alertSummary.queryByText('Rule')).toBeInTheDocument(); + expect( + alertSummary.queryByText(alertWithGroupsAndTags.fields[ALERT_RULE_NAME]) + ).toBeInTheDocument(); expect(alertSummary.queryByText('Actual value')).toBeInTheDocument(); - expect(alertSummary.queryByText(alertWithTags.fields['kibana.alert.evaluation.value']!)); + expect(alertSummary.queryByText(alertWithGroupsAndTags.fields[ALERT_EVALUATION_VALUE]!)); expect(alertSummary.queryByText('Expected value')).toBeInTheDocument(); - expect(alertSummary.queryByText(alertWithTags.fields['kibana.alert.evaluation.threshold']!)); + expect(alertSummary.queryByText(alertWithGroupsAndTags.fields[ALERT_EVALUATION_THRESHOLD]!)); }); }); diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_summary.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_summary.tsx index 20d0fb36f9f8a4..82c22626aab858 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_summary.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_summary.tsx @@ -5,24 +5,97 @@ * 2.0. */ -import React, { ReactNode } from 'react'; -import { EuiFlexItem, EuiFlexGroup, EuiText, EuiSpacer } from '@elastic/eui'; +import React, { useEffect, useState, ReactNode } from 'react'; +import { EuiFlexItem, EuiFlexGroup, EuiText, EuiSpacer, EuiLink } from '@elastic/eui'; +import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; +import { + TAGS, + ALERT_START, + ALERT_END, + ALERT_RULE_NAME, + ALERT_RULE_UUID, +} from '@kbn/rule-data-utils'; +import { i18n } from '@kbn/i18n'; +import { TimeRange } from '@kbn/es-query'; +import { TopAlert } from '../../..'; +import { Groups } from '../../../components/alert_sources/groups'; +import { Tags } from '../../../components/tags'; +import { getSources } from '../../../components/alert_sources/get_sources'; +import { useKibana } from '../../../utils/kibana_react'; +import { paths } from '../../../../common/locators/paths'; export interface AlertSummaryField { label: ReactNode | string; value: ReactNode | string | number; } interface AlertSummaryProps { + alert: TopAlert; alertSummaryFields?: AlertSummaryField[]; } -export function AlertSummary({ alertSummaryFields }: AlertSummaryProps) { +export function AlertSummary({ alert, alertSummaryFields }: AlertSummaryProps) { + const { http } = useKibana().services; + + const [timeRange, setTimeRange] = useState({ from: 'now-15m', to: 'now' }); + + const alertStart = alert.fields[ALERT_START]; + const alertEnd = alert.fields[ALERT_END]; + const ruleName = alert.fields[ALERT_RULE_NAME]; + const ruleId = alert.fields[ALERT_RULE_UUID]; + const tags = alert.fields[TAGS]; + + const ruleLink = http.basePath.prepend(paths.observability.ruleDetails(ruleId)); + const commonFieldsAtStart = []; + const commonFieldsAtEnd = []; + const groups = getSources(alert) as Array<{ field: string; value: string }>; + + useEffect(() => { + setTimeRange(getPaddedAlertTimeRange(alertStart!, alertEnd)); + }, [alertStart, alertEnd]); + + if (groups && groups.length > 0) { + commonFieldsAtStart.push({ + label: i18n.translate('xpack.observability.alertDetails.alertSummaryField.source', { + defaultMessage: 'Source', + }), + value: ( + + ), + }); + } + + if (tags && tags.length > 0) { + commonFieldsAtEnd.push({ + label: i18n.translate('xpack.observability.alertDetails.alertSummaryField.tags', { + defaultMessage: 'Tags', + }), + value: , + }); + } + + commonFieldsAtEnd.push({ + label: i18n.translate('xpack.observability.alertDetails.alertSummaryField.rule', { + defaultMessage: 'Rule', + }), + value: ( + + {ruleName} + + ), + }); + + const alertSummary = [ + ...commonFieldsAtStart, + ...(alertSummaryFields ?? []), + ...commonFieldsAtEnd, + ]; + return (
- {alertSummaryFields && alertSummaryFields.length > 0 && ( + {alertSummary && alertSummary.length > 0 && ( <> - {alertSummaryFields.map((field, idx) => { + {alertSummary.map((field, idx) => { return ( {field.label} diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.test.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.test.tsx index 6c07c54f604543..b3e28ba222c5a3 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.test.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.test.tsx @@ -13,7 +13,7 @@ import { casesPluginMock } from '@kbn/cases-plugin/public/mocks'; import { render } from '../../../utils/test_helper'; import { useKibana } from '../../../utils/kibana_react'; import { kibanaStartMock } from '../../../utils/kibana_react.mock'; -import { alertWithTags, mockAlertUuid, untrackedAlert } from '../mock/alert'; +import { alertWithGroupsAndTags, mockAlertUuid, untrackedAlert } from '../mock/alert'; import { useFetchRule } from '../../../hooks/use_fetch_rule'; import { HeaderActions } from './header_actions'; @@ -87,8 +87,8 @@ describe('Header Actions', () => { it('should display an actions button', () => { const { queryByTestId } = render( ); @@ -109,9 +109,9 @@ describe('Header Actions', () => { const { getByTestId, findByTestId } = render( ); @@ -136,8 +136,8 @@ describe('Header Actions', () => { it('should offer a "Edit rule" button which opens the edit rule flyout', async () => { const { getByTestId, findByTestId } = render( ); @@ -150,8 +150,8 @@ describe('Header Actions', () => { it('should offer a "Mark as untracked" button which is enabled', async () => { const { queryByTestId, findByTestId } = render( ); @@ -163,8 +163,8 @@ describe('Header Actions', () => { it('should offer a "Go to rule details" button which opens the rule details page in a new tab', async () => { const { queryByTestId, findByTestId } = render( ); @@ -188,8 +188,8 @@ describe('Header Actions', () => { it("should disable the 'Edit rule' when the rule is not available/deleted", async () => { const { queryByTestId, findByTestId } = render( ); @@ -214,8 +214,8 @@ describe('Header Actions', () => { it("should disable the 'View rule details' when the rule is not available/deleted", async () => { const { queryByTestId, findByTestId } = render( ); diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/mock/alert.ts b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/mock/alert.ts index 5f377aab476863..3474f9b40674b1 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/mock/alert.ts +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/mock/alert.ts @@ -9,6 +9,7 @@ import { ALERT_DURATION, ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_VALUE, + ALERT_GROUP, ALERT_INSTANCE_ID, ALERT_REASON, ALERT_RULE_CATEGORY, @@ -27,6 +28,7 @@ import { EVENT_ACTION, EVENT_KIND, SPACE_IDS, + TAGS, TIMESTAMP, VERSION, } from '@kbn/rule-data-utils'; @@ -75,18 +77,23 @@ export const alertDetail: AlertData = { ) as unknown as AlertData['raw'], }; -export const alertWithTags: TopAlert = { +export const alertWithGroupsAndTags: TopAlert = { ...alert, fields: { ...alert.fields, + [ALERT_GROUP]: [ + { field: 'host.name', value: 'host-0' }, + { field: 'container.id', value: 'container-0' }, + ], [ALERT_RULE_TAGS]: tags, + [TAGS]: tags, }, }; export const untrackedAlert: TopAlert = { - ...alertWithTags, + ...alertWithGroupsAndTags, fields: { - ...alertWithTags.fields, + ...alertWithGroupsAndTags.fields, [ALERT_STATUS]: ALERT_STATUS_UNTRACKED, }, }; diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/mock/alert_summary_fields.ts b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/mock/alert_summary_fields.ts index 304f750009e8d5..b80890c7f73af3 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/mock/alert_summary_fields.ts +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/mock/alert_summary_fields.ts @@ -5,20 +5,17 @@ * 2.0. */ -import { alertWithTags } from './alert'; +import { ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_VALUE } from '@kbn/rule-data-utils'; +import { alertWithGroupsAndTags } from './alert'; import type { AlertSummaryField } from '../components/alert_summary'; export const alertSummaryFieldsMock: AlertSummaryField[] = [ { label: 'Actual value', - value: alertWithTags.fields['kibana.alert.evaluation.value']!, + value: alertWithGroupsAndTags.fields[ALERT_EVALUATION_VALUE]!, }, { label: 'Expected value', - value: alertWithTags.fields['kibana.alert.evaluation.threshold']!, - }, - { - label: 'Source', - value: '-', + value: alertWithGroupsAndTags.fields[ALERT_EVALUATION_THRESHOLD]!, }, ]; diff --git a/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts b/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts index 94be15415abb8a..baec846b711547 100644 --- a/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts +++ b/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/custom_threshold_executor.ts @@ -17,7 +17,6 @@ import { LocatorPublic } from '@kbn/share-plugin/common'; import { RecoveredActionGroup } from '@kbn/alerting-plugin/common'; import { IBasePath, Logger } from '@kbn/core/server'; import { AlertsClientError, RuleExecutorOptions } from '@kbn/alerting-plugin/server'; -import { Group } from '../../../../common/custom_threshold_rule/types'; import { getEvaluationValues, getThreshold } from './lib/get_values'; import { AlertsLocatorParams, getAlertDetailsUrl } from '../../../../common'; import { getViewInAppUrl } from '../../../../common/custom_threshold_rule/get_view_in_app_url'; @@ -46,6 +45,7 @@ import { import { formatAlertResult, getLabel } from './lib/format_alert_result'; import { EvaluatedRuleParams, evaluateRule } from './lib/evaluate_rule'; import { MissingGroupsRecord } from './lib/check_missing_group'; +import { Group } from '../../../../common/typings'; export interface CustomThresholdLocators { alertsLocator?: LocatorPublic; diff --git a/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/types.ts b/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/types.ts index 6f1e8cf72cc7df..052741c474f46f 100644 --- a/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/types.ts +++ b/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/types.ts @@ -18,9 +18,9 @@ import { ALERT_EVALUATION_VALUES, ALERT_GROUP, } from '@kbn/rule-data-utils'; +import { Group } from '../../../../common/typings'; import { CustomMetricExpressionParams, - Group, SearchConfigurationWithExtractedReferenceType, } from '../../../../common/custom_threshold_rule/types'; import { FIRED_ACTIONS_ID, NO_DATA_ACTIONS_ID, FIRED_ACTION, NO_DATA_ACTION } from './constants'; diff --git a/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/utils.ts b/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/utils.ts index 88f1febca71c09..c80a003c050e07 100644 --- a/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/utils.ts +++ b/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/utils.ts @@ -17,7 +17,7 @@ import { set } from '@kbn/safer-lodash-set'; import { ParsedExperimentalFields } from '@kbn/rule-registry-plugin/common/parse_experimental_fields'; import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; import { Alert } from '@kbn/alerts-as-data-utils'; -import type { Group } from '../../../../common/custom_threshold_rule/types'; +import type { Group } from '../../../../common/typings'; import { ObservabilityConfig } from '../../..'; import { AlertExecutionDetails } from './types'; diff --git a/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/alert_details_app_section.tsx b/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/alert_details_app_section.tsx index 324c84c9d923fe..be83b74a0cc195 100644 --- a/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/alert_details_app_section.tsx +++ b/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/alert_details_app_section.tsx @@ -7,10 +7,8 @@ import { EuiFlexGroup, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { AlertSummaryField } from '@kbn/observability-plugin/public'; -import { ALL_VALUE } from '@kbn/slo-schema'; import React, { useEffect } from 'react'; import { useFetchSloDetails } from '../../../../hooks/use_fetch_slo_details'; -import { SLOGroupings } from '../../../../pages/slos/components/common/slo_groupings'; import { useKibana } from '../../../../utils/kibana_react'; import { CustomAlertDetailsPanel } from './components/custom_panels/custom_panels'; import { ErrorRatePanel } from './components/error_rate/error_rate_panel'; @@ -19,7 +17,6 @@ import { BurnRateAlert, BurnRateRule } from './types'; interface AppSectionProps { alert: BurnRateAlert; rule: BurnRateRule; - ruleLink: string; setAlertSummaryFields: React.Dispatch>; } @@ -27,7 +24,6 @@ interface AppSectionProps { export default function AlertDetailsAppSection({ alert, rule, - ruleLink, setAlertSummaryFields, }: AppSectionProps) { const { @@ -45,7 +41,7 @@ export default function AlertDetailsAppSection({ const fields = [ { label: i18n.translate('xpack.slo.burnRateRule.alertDetailsAppSection.summaryField.slo', { - defaultMessage: 'Source SLO', + defaultMessage: 'SLO', }), value: ( @@ -53,30 +49,10 @@ export default function AlertDetailsAppSection({ ), }, - { - label: i18n.translate('xpack.slo.burnRateRule.alertDetailsAppSection.summaryField.rule', { - defaultMessage: 'Rule', - }), - value: ( - - {rule.name} - - ), - }, ]; - if (instanceId !== ALL_VALUE) { - fields.push({ - label: i18n.translate( - 'xpack.slo.burnRateRule.alertDetailsAppSection.summaryField.instanceId', - { defaultMessage: 'SLO Instance' } - ), - value: , - }); - } - setAlertSummaryFields(fields); - }, [alertLink, rule, ruleLink, setAlertSummaryFields, basePath, slo, instanceId]); + }, [alertLink, rule, setAlertSummaryFields, basePath, slo, instanceId]); return ( diff --git a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts index ebbfff071bbe34..1b3ddb32c56f86 100644 --- a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts @@ -9,7 +9,6 @@ import { SanitizedRuleConfig } from '@kbn/alerting-plugin/common'; import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common/rules_settings'; import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; import { publicAlertsClientMock } from '@kbn/alerting-plugin/server/alerts_client/alerts_client.mock'; -import { ObservabilitySloAlert } from '@kbn/alerts-as-data-utils'; import { IBasePath, IUiSettingsClient, @@ -47,6 +46,7 @@ import { import { ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_VALUE, + ALERT_GROUP, ALERT_REASON, SLO_BURN_RATE_RULE_TYPE_ID, } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; @@ -54,7 +54,7 @@ import { SLODefinition, StoredSLODefinition } from '../../../domain/models'; import { SLONotFound } from '../../../errors'; import { SO_SLO_TYPE } from '../../../saved_objects'; import { createSLO } from '../../../services/fixtures/slo'; -import { getRuleExecutor } from './executor'; +import { BurnRateAlert, getRuleExecutor } from './executor'; import { generateAboveThresholdKey, generateBurnRateKey, @@ -163,7 +163,7 @@ describe('BurnRateRuleExecutor', () => { BurnRateAlertState, BurnRateAlertContext, BurnRateAllowedActionGroups, - ObservabilitySloAlert + BurnRateAlert > >; @@ -338,7 +338,7 @@ describe('BurnRateRuleExecutor', () => { }); it('schedules an alert when both windows of first window definition burn rate have reached the threshold', async () => { - const slo = createSLO({ objective: { target: 0.9 } }); + const slo = createSLO({ objective: { target: 0.9 }, groupBy: ['group.by.field'] }); const ruleParams = someRuleParamsWithWindows({ sloId: slo.id }); soClientMock.find.mockResolvedValueOnce(createFindResponse([slo])); const buckets = [ @@ -404,6 +404,12 @@ describe('BurnRateRuleExecutor', () => { [SLO_ID_FIELD]: slo.id, [SLO_REVISION_FIELD]: slo.revision, [SLO_INSTANCE_ID_FIELD]: 'foo', + [ALERT_GROUP]: [ + { + field: 'group.by.field', + value: 'foo', + }, + ], }, }); expect(servicesMock.alertsClient?.report).toBeCalledWith({ @@ -420,6 +426,12 @@ describe('BurnRateRuleExecutor', () => { [SLO_ID_FIELD]: slo.id, [SLO_REVISION_FIELD]: slo.revision, [SLO_INSTANCE_ID_FIELD]: 'bar', + [ALERT_GROUP]: [ + { + field: 'group.by.field', + value: 'bar', + }, + ], }, }); expect(servicesMock.alertsClient?.setAlertData).toHaveBeenNthCalledWith(1, { @@ -454,7 +466,7 @@ describe('BurnRateRuleExecutor', () => { }); it('schedules a suppressed alert when both windows of first window definition burn rate have reached the threshold but the dependency matches', async () => { - const slo = createSLO({ objective: { target: 0.9 } }); + const slo = createSLO({ objective: { target: 0.9 }, groupBy: ['group.by.field'] }); const dependencyRuleParams = someRuleParamsWithWindows({ sloId: slo.id }); const ruleParams = someRuleParamsWithWindows({ sloId: slo.id, @@ -538,6 +550,12 @@ describe('BurnRateRuleExecutor', () => { [SLO_ID_FIELD]: slo.id, [SLO_REVISION_FIELD]: slo.revision, [SLO_INSTANCE_ID_FIELD]: 'foo', + [ALERT_GROUP]: [ + { + field: 'group.by.field', + value: 'foo', + }, + ], }, }); expect(servicesMock.alertsClient?.report).toBeCalledWith({ @@ -554,6 +572,12 @@ describe('BurnRateRuleExecutor', () => { [SLO_ID_FIELD]: slo.id, [SLO_REVISION_FIELD]: slo.revision, [SLO_INSTANCE_ID_FIELD]: 'bar', + [ALERT_GROUP]: [ + { + field: 'group.by.field', + value: 'bar', + }, + ], }, }); expect(servicesMock.alertsClient?.setAlertData).toHaveBeenNthCalledWith(1, { @@ -588,7 +612,7 @@ describe('BurnRateRuleExecutor', () => { }); it('schedules an alert when both windows of second window definition burn rate have reached the threshold', async () => { - const slo = createSLO({ objective: { target: 0.9 } }); + const slo = createSLO({ objective: { target: 0.9 }, groupBy: ['group.by.field'] }); const ruleParams = someRuleParamsWithWindows({ sloId: slo.id }); soClientMock.find.mockResolvedValueOnce(createFindResponse([slo])); const buckets = [ @@ -653,6 +677,12 @@ describe('BurnRateRuleExecutor', () => { [SLO_ID_FIELD]: slo.id, [SLO_REVISION_FIELD]: slo.revision, [SLO_INSTANCE_ID_FIELD]: 'foo', + [ALERT_GROUP]: [ + { + field: 'group.by.field', + value: 'foo', + }, + ], }, }); expect(servicesMock.alertsClient!.report).toBeCalledWith({ @@ -669,6 +699,12 @@ describe('BurnRateRuleExecutor', () => { [SLO_ID_FIELD]: slo.id, [SLO_REVISION_FIELD]: slo.revision, [SLO_INSTANCE_ID_FIELD]: 'bar', + [ALERT_GROUP]: [ + { + field: 'group.by.field', + value: 'bar', + }, + ], }, }); diff --git a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.ts b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.ts index 0df4a07fa70c15..1e4be6e78b88e2 100644 --- a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.ts +++ b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.ts @@ -10,6 +10,7 @@ import numeral from '@elastic/numeral'; import { ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_VALUE, + ALERT_GROUP, ALERT_REASON, } from '@kbn/rule-data-utils'; import { AlertsClientError, RuleExecutorOptions } from '@kbn/alerting-plugin/server'; @@ -36,6 +37,7 @@ import { BurnRateAllowedActionGroups, BurnRateRuleParams, BurnRateRuleTypeState, + Group, WindowSchema, } from './types'; import { @@ -50,6 +52,10 @@ import { evaluateDependencies } from './lib/evaluate_dependencies'; import { shouldSuppressInstanceId } from './lib/should_suppress_instance_id'; import { getSloSummary } from './lib/summary_repository'; +export type BurnRateAlert = Omit & { + [ALERT_GROUP]?: Group[]; +}; + export const getRuleExecutor = ({ basePath, alertsLocator, @@ -64,7 +70,7 @@ export const getRuleExecutor = ({ BurnRateAlertState, BurnRateAlertContext, BurnRateAllowedActionGroups, - ObservabilitySloAlert + BurnRateAlert > ): ReturnType< ExecutorType< @@ -123,6 +129,15 @@ export const getRuleExecutor = ({ window: windowDef, } = result; + const instances = instanceId.split(','); + const groups = + instanceId !== ALL_VALUE + ? [slo.groupBy].flat().reduce((resultGroups, groupByItem, index) => { + resultGroups.push({ field: groupByItem, value: instances[index].trim() }); + return resultGroups; + }, []) + : undefined; + const urlQuery = instanceId === ALL_VALUE ? '' : `?instanceId=${instanceId}`; const viewInAppUrl = addSpaceIdToPath( basePath.publicBaseUrl, @@ -165,6 +180,7 @@ export const getRuleExecutor = ({ [ALERT_REASON]: reason, [ALERT_EVALUATION_THRESHOLD]: windowDef.burnRateThreshold, [ALERT_EVALUATION_VALUE]: Math.min(longWindowBurnRate, shortWindowBurnRate), + [ALERT_GROUP]: groups, [SLO_ID_FIELD]: slo.id, [SLO_REVISION_FIELD]: slo.revision, [SLO_INSTANCE_ID_FIELD]: instanceId, diff --git a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/types.ts b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/types.ts index be7442749d625e..c63306fb0df26c 100644 --- a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/types.ts +++ b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/types.ts @@ -52,3 +52,8 @@ export type BurnRateAllowedActionGroups = ActionGroupIdsOf< | typeof LOW_PRIORITY_ACTION | typeof SUPPRESSED_PRIORITY_ACTION >; + +export interface Group { + field: string; + value: string; +} diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index fd47cd081f8780..673bfbcfe49ff4 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -9436,8 +9436,6 @@ "xpack.apm.onboarding.shared_clients.configure.commands.serviceNameHint": "Le nom de service est le filtre principal dans l'interface utilisateur APM et est utilisé pour regrouper les erreurs et suivre les données ensemble. Caractères autorisés : a-z, A-Z, 0-9, -, _ et espace.", "xpack.apm.pages.alertDetails.alertSummary.actualValue": "Valeur réelle", "xpack.apm.pages.alertDetails.alertSummary.expectedValue": "Valeur attendue", - "xpack.apm.pages.alertDetails.alertSummary.serviceEnv": "Environnement de service", - "xpack.apm.pages.alertDetails.alertSummary.serviceName": "Nom de service", "xpack.apm.profiling.callout.description": "Universal Profiling fournit une visibilité sans précédent du code au milieu du comportement en cours d'exécution de toutes les applications. La fonctionnalité profile chaque ligne de code chez le ou les hôtes qui exécutent vos services, y compris votre code applicatif, le kernel et même les bibliothèque tierces.", "xpack.apm.profiling.callout.dismiss": "Rejeter", "xpack.apm.profiling.callout.learnMore": "En savoir plus", @@ -21393,7 +21391,6 @@ "xpack.infra.metricDetailPage.sqsMetricsLayout.oldestMessage.chartLabel": "Âge", "xpack.infra.metricDetailPage.sqsMetricsLayout.oldestMessage.sectionLabel": "Message le plus ancien", "xpack.infra.metricDetailPage.sqsMetricsLayout.overviewSection.sectionLabel": "Aperçu SQS AWS", - "xpack.infra.metrics.alertDetailsAppSection.summaryField.rule": "Règle", "xpack.infra.metrics.alertDetailsAppSection.thresholdTitle": "Seuil dépassé", "xpack.infra.metrics.alertFlyout.addCondition": "Ajouter une condition", "xpack.infra.metrics.alertFlyout.addWarningThreshold": "Ajouter un seuil d'avertissement", @@ -29585,7 +29582,6 @@ "xpack.observability.customThreshold.rule.aggregators.p99": "99e centile de {metric}", "xpack.observability.customThreshold.rule.aggregators.rate": "Taux de {metric}", "xpack.observability.customThreshold.rule.aggregators.sum": "Somme de {metric}", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.moreTags": "+{number} de plus", "xpack.observability.customThreshold.rule.alertFlyout.alertPerRedundantFilterError": "Il est possible que cette règle signale {matchedGroups} moins que prévu, car la requête de filtre comporte une correspondance pour {groupCount, plural, one {ce champ} other {ces champs}}. Pour en savoir plus, veuillez consulter {filteringAndGroupingLink}.", "xpack.observability.customThreshold.rule.alertFlyout.condition": "Condition {conditionNumber}", "xpack.observability.customThreshold.rule.alertFlyout.customEquationEditor.aggregationLabel": "{name} de l'agrégation", @@ -29700,10 +29696,6 @@ "xpack.observability.customThreshold.rule..timeLabels.seconds": "secondes", "xpack.observability.customThreshold.rule.aggregators.customEquation": "Équation personnalisée", "xpack.observability.customThreshold.rule.aggregators.documentCount": "Nombre de documents", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.moreTags.ariaLabel": "badge plus de balises", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.rule": "Règle", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.source": "Source", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.tags": "Balises", "xpack.observability.customThreshold.rule.alertDetailsAppSection.thresholdTitle": "Seuil dépassé", "xpack.observability.customThreshold.rule.alertDetailUrlActionVariableDescription": "Lien vers l’affichage de résolution des problèmes d’alerte pour voir plus de contextes et de détails. La chaîne sera vide si server.publicBaseUrl n'est pas configuré.", "xpack.observability.customThreshold.rule.alertFlyout.addCondition": "Ajouter une condition", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 7e2f411d770c2a..56df15a9c73bd2 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9416,8 +9416,6 @@ "xpack.apm.onboarding.shared_clients.configure.commands.serviceNameHint": "このサービス名はAPM UIの主フィルターであり、エラーとトレースデータをグループ化するために使用されます。使用できる文字はA-Z、0-9、-、_、スペースです。", "xpack.apm.pages.alertDetails.alertSummary.actualValue": "実際の値", "xpack.apm.pages.alertDetails.alertSummary.expectedValue": "想定された値", - "xpack.apm.pages.alertDetails.alertSummary.serviceEnv": "サービス環境", - "xpack.apm.pages.alertDetails.alertSummary.serviceName": "サービス名", "xpack.apm.profiling.callout.description": "ユニバーサルプロファイリングは、すべてのアプリケーションの実行時の動作に関して、かつてないほどコードを可視化します。アプリケーションコードだけでなく、カーネルやサードパーティライブラリも含め、サービスを実行するホスト上のすべてのコード行をプロファイリングします。", "xpack.apm.profiling.callout.dismiss": "閉じる", "xpack.apm.profiling.callout.learnMore": "詳細", @@ -21368,7 +21366,6 @@ "xpack.infra.metricDetailPage.sqsMetricsLayout.oldestMessage.chartLabel": "年齢", "xpack.infra.metricDetailPage.sqsMetricsLayout.oldestMessage.sectionLabel": "最も古いメッセージ", "xpack.infra.metricDetailPage.sqsMetricsLayout.overviewSection.sectionLabel": "Aws SQS概要", - "xpack.infra.metrics.alertDetailsAppSection.summaryField.rule": "ルール", "xpack.infra.metrics.alertDetailsAppSection.thresholdTitle": "しきい値を超えました", "xpack.infra.metrics.alertFlyout.addCondition": "条件を追加", "xpack.infra.metrics.alertFlyout.addWarningThreshold": "警告しきい値を追加", @@ -29562,7 +29559,6 @@ "xpack.observability.customThreshold.rule.aggregators.p99": "{metric}の99パーセンタイル", "xpack.observability.customThreshold.rule.aggregators.rate": "{metric}の比率", "xpack.observability.customThreshold.rule.aggregators.sum": "{metric}の合計", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.moreTags": "その他{number}", "xpack.observability.customThreshold.rule.alertFlyout.alertPerRedundantFilterError": "このルールは想定未満の{matchedGroups}に対してアラートを通知できます。フィルタークエリには{groupCount, plural, one {このフィールド} other {これらのフィールド}}の完全一致が含まれるためです。詳細については、{filteringAndGroupingLink}を参照してください。", "xpack.observability.customThreshold.rule.alertFlyout.condition": "条件{conditionNumber}", "xpack.observability.customThreshold.rule.alertFlyout.customEquationEditor.aggregationLabel": "集約{name}", @@ -29678,10 +29674,6 @@ "xpack.observability.customThreshold.rule..timeLabels.seconds": "秒", "xpack.observability.customThreshold.rule.aggregators.customEquation": "カスタム等式", "xpack.observability.customThreshold.rule.aggregators.documentCount": "ドキュメントカウント", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.moreTags.ariaLabel": "その他のタグバッジ", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.rule": "ルール", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.source": "送信元", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.tags": "タグ", "xpack.observability.customThreshold.rule.alertDetailsAppSection.thresholdTitle": "しきい値を超えました", "xpack.observability.customThreshold.rule.alertDetailUrlActionVariableDescription": "アラートトラブルシューティングビューにリンクして、さらに詳しい状況や詳細を確認できます。server.publicBaseUrlが構成されていない場合は、空の文字列になります。", "xpack.observability.customThreshold.rule.alertFlyout.addCondition": "条件を追加", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d43efdcf980fb1..48d126c33a1e96 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9439,8 +9439,6 @@ "xpack.apm.onboarding.shared_clients.configure.commands.serviceNameHint": "服务名称是 APM UI 中的初级筛选,用于分组错误并跟踪数据。允许使用的字符包括 a-z、A-Z、0-9、-、_ 和空格。", "xpack.apm.pages.alertDetails.alertSummary.actualValue": "实际值", "xpack.apm.pages.alertDetails.alertSummary.expectedValue": "预期值", - "xpack.apm.pages.alertDetails.alertSummary.serviceEnv": "服务环境", - "xpack.apm.pages.alertDetails.alertSummary.serviceName": "服务名称", "xpack.apm.profiling.callout.description": "Universal Profiling 为所有应用程序的运行时行为提供了前所未有的代码可见性。它会剖析运行服务的主机上的每一行代码,不仅包括您的应用程序代码,而且包括内核和第三方库。", "xpack.apm.profiling.callout.dismiss": "关闭", "xpack.apm.profiling.callout.learnMore": "了解详情", @@ -21400,7 +21398,6 @@ "xpack.infra.metricDetailPage.sqsMetricsLayout.oldestMessage.chartLabel": "存在时间", "xpack.infra.metricDetailPage.sqsMetricsLayout.oldestMessage.sectionLabel": "最旧消息", "xpack.infra.metricDetailPage.sqsMetricsLayout.overviewSection.sectionLabel": "Aws SQS 概览", - "xpack.infra.metrics.alertDetailsAppSection.summaryField.rule": "规则", "xpack.infra.metrics.alertDetailsAppSection.thresholdTitle": "超出阈值", "xpack.infra.metrics.alertFlyout.addCondition": "添加条件", "xpack.infra.metrics.alertFlyout.addWarningThreshold": "添加警告阈值", @@ -29602,7 +29599,6 @@ "xpack.observability.customThreshold.rule.aggregators.p99": "{metric} 的第 99 个百分位", "xpack.observability.customThreshold.rule.aggregators.rate": "{metric} 的比率", "xpack.observability.customThreshold.rule.aggregators.sum": "{metric} 的总和", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.moreTags": "+ 另外 {number} 个", "xpack.observability.customThreshold.rule.alertFlyout.alertPerRedundantFilterError": "此规则可能针对低于预期的 {matchedGroups} 告警,因为筛选查询包含{groupCount, plural, one {此字段} other {这些字段}}的匹配项。有关更多信息,请参阅 {filteringAndGroupingLink}。", "xpack.observability.customThreshold.rule.alertFlyout.condition": "条件 {conditionNumber}", "xpack.observability.customThreshold.rule.alertFlyout.customEquationEditor.aggregationLabel": "聚合 {name}", @@ -29718,10 +29714,6 @@ "xpack.observability.customThreshold.rule..timeLabels.seconds": "秒", "xpack.observability.customThreshold.rule.aggregators.customEquation": "定制方程", "xpack.observability.customThreshold.rule.aggregators.documentCount": "文档计数", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.moreTags.ariaLabel": "更多标签徽章", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.rule": "规则", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.source": "源", - "xpack.observability.customThreshold.rule.alertDetailsAppSection.summaryField.tags": "标签", "xpack.observability.customThreshold.rule.alertDetailsAppSection.thresholdTitle": "超出阈值", "xpack.observability.customThreshold.rule.alertDetailUrlActionVariableDescription": "链接到告警故障排除视图获取进一步的上下文和详情。如果未配置 server.publicBaseUrl,这将为空字符串。", "xpack.observability.customThreshold.rule.alertFlyout.addCondition": "添加条件", From f820f788072ebd48613ee0b8074abf06605263f7 Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Tue, 18 Jun 2024 08:21:48 -0400 Subject: [PATCH 023/123] [Security Solution][Endpoint] Refactor UI response actions code (#184543) ## Summary This PR does a major refactor of Response Actions functionality usage outside of the `management` section of the code base. The impact (although should be transparent from a user's standpoint) is mostly to the Alert Details "Take Action" menu and specifically to the "Isolate/Release" and "Respond" menu actions and the UI's it displays when clicked. The changes can be summarized as: - Centralized (moved) all code associated with Response Actions under one of the following three directories: - `public/common/component/endpoint` - `public/common/hooks/endpoint` - `public/common/lib/endpoint` - Most changed files in this PR were a result of this activity - Deleted several utilities that were used to determine the Alert's host support for Response actions and replaced with a single `hook` (`useAlertResponseActionsSupport()`) - The "Isolate/Release" Take Action menu item now behaves similar to the "Respond" menu option (on Alerts) in that: - Its only NOT displayed if the user is not authorized to use it - It will show up as disabled while we are attempting to determine support for response actions on the alert's host - Tooltips will be displayed when options is disabled --- .github/CODEOWNERS | 11 +- .../service/host_isolation/utils.test.ts | 84 ----- .../endpoint/service/host_isolation/utils.ts | 83 ----- .../service/response_actions/constants.ts | 11 + .../public/cases/pages/index.tsx | 2 +- .../agent_response_action_status.tsx | 8 +- .../agents/agent_status/agent_status.test.tsx | 14 +- .../agents/agent_status/agent_status.tsx | 12 +- .../endpoint/endpoint_agent_status.test.tsx | 24 +- .../endpoint/endpoint_agent_status.tsx | 16 +- .../agents/agent_status/index.ts | 0 .../agents/agent_status_text.ts | 2 +- .../host_isolation/__mocks__}/index.ts | 2 +- .../from_alerts/__mocks__/index.ts | 8 + .../__mocks__/use_host_isolation_action.tsx | 23 ++ .../host_isolation_panel.test.tsx} | 44 +-- .../from_alerts/host_isolation_panel.tsx | 74 +++++ .../host_isolation/from_alerts/index.ts | 10 + .../host_isolation/from_alerts}/isolate.tsx | 13 +- .../from_alerts}/translations.ts | 0 .../host_isolation/from_alerts}/unisolate.tsx | 13 +- .../from_alerts}/use_host_isolation.tsx | 8 +- .../use_host_isolation_action.test.tsx | 144 +++++++++ .../from_alerts/use_host_isolation_action.tsx | 175 +++++++++++ .../use_host_isolation_status.tsx | 26 +- .../from_alerts}/use_host_unisolation.tsx | 8 +- .../endpoint_host_isolation_cases_context.tsx | 0 .../host_isolation/from_cases/index.ts | 8 + .../endpoint/host_isolation/index.ts | 2 + .../common/components/endpoint/index.ts | 11 + .../endpoint/responder/__mocks__/index.ts | 8 + .../responder/from_alerts/__mocks__/index.ts | 9 + .../__mocks__/use_responder_action_data.ts | 24 ++ .../__mocks__/use_responder_action_item.tsx | 24 ++ .../endpoint/responder/from_alerts/index.ts | 11 + .../from_alerts}/responder_action_button.tsx | 15 +- .../responder/from_alerts}/translations.ts | 21 -- .../use_responder_action_data.test.ts | 283 +++++++++++++++++ .../from_alerts/use_responder_action_data.ts | 271 +++++++++++++++++ .../use_responder_action_item.test.tsx | 61 ++++ .../use_responder_action_item.tsx | 44 +-- .../components/endpoint/responder/index.ts | 8 + .../get_alert_summary_rows.test.ts | 156 +++------- .../event_details/get_alert_summary_rows.tsx | 78 ++--- .../components/event_details/helpers.tsx | 7 +- .../use_alert_response_actions_support.ts | 35 +++ ...use_alert_response_actions_support.test.ts | 207 +++++++++++++ .../use_alert_response_actions_support.ts | 241 +++++++++++++++ .../endpoint_isolation/index.test.ts | 6 +- .../endpoint_isolation/index.ts | 8 +- .../endpoint_isolation/mocks.ts | 8 +- .../endpoint_pending_actions.test.ts | 6 +- .../endpoint_pending_actions.ts | 8 +- .../endpoint_pending_actions/index.ts | 0 .../endpoint_pending_actions/mocks.ts | 8 +- .../public/common/lib/endpoint/index.ts | 10 + .../utils/get_event_details_field_values.ts} | 32 +- .../public/common/lib/endpoint/utils/index.ts | 9 + ...is_agent_type_and_action_supported.test.ts | 82 +++++ .../is_agent_type_and_action_supported.ts | 60 ++++ ...s_response_actions_alert_agent_id_field.ts | 19 ++ .../mock/endpoint/endpoint_alert_data_mock.ts | 248 +++++++++++++++ .../public/common/mock/endpoint/index.ts | 2 + .../public/common/translations.ts | 2 +- .../utils/crowdstrike_alert_check.test.ts | 69 ----- .../common/utils/crowdstrike_alert_check.ts | 69 ----- .../common/utils/endpoint_alert_check.test.ts | 85 ------ .../common/utils/endpoint_alert_check.ts | 53 ---- .../common/utils/sentinelone_alert_check.ts | 64 ---- .../timeline_actions/alert_context_menu.tsx | 12 +- .../get_external_edr_agent_info.test.ts | 120 -------- .../get_external_edr_agent_info.ts | 70 ----- .../use_responder_action_data.test.ts | 233 -------------- .../use_responder_action_data.ts | 175 ----------- .../use_responder_action_item.test.tsx | 144 --------- .../components/host_isolation/index.tsx | 94 ------ .../use_host_isolation_action.test.tsx | 163 ---------- .../use_host_isolation_action.tsx | 272 ----------------- .../take_action_dropdown/index.test.tsx | 287 +++--------------- .../components/take_action_dropdown/index.tsx | 26 +- .../containers/detection_engine/alerts/api.ts | 2 +- .../explore/hosts/pages/details/index.tsx | 4 +- .../document_details/isolate_host/content.tsx | 6 +- .../isolate_host/header.test.tsx | 169 +++++------ .../document_details/isolate_host/header.tsx | 49 ++- .../components/highlighted_fields_cell.tsx | 9 +- .../hooks/use_highlighted_fields.test.tsx | 8 +- .../shared/hooks/use_highlighted_fields.ts | 36 +-- .../fields/endpoint_policy_fields.tsx | 2 +- .../status_action.tsx | 2 +- .../header_info/agent_info/agent_info.tsx | 2 +- .../endpoint/header_endpoint_info.tsx | 2 +- .../sentinel_one/header_sentinel_one_info.tsx | 2 +- .../components/offline_callout.tsx | 23 +- .../lib/console_commands_definition.ts | 79 ++--- ...se_get_endpoint_pending_actions_summary.ts | 2 +- .../use_send_isolate_endpoint_request.ts | 2 +- .../use_send_release_endpoint_request.ts | 2 +- .../management/pages/endpoint_hosts/mocks.ts | 4 +- .../endpoint_hosts/store/middleware.test.ts | 2 +- .../pages/endpoint_hosts/store/middleware.ts | 4 +- .../store/mock_endpoint_result_list.ts | 2 +- .../view/details/endpoint_details_content.tsx | 2 +- .../view/hooks/use_endpoint_action_items.tsx | 8 +- .../pages/endpoint_hosts/view/index.test.tsx | 2 +- .../pages/endpoint_hosts/view/index.tsx | 2 +- .../host_overview/endpoint_overview/index.tsx | 2 +- .../flyout/back_to_alert_details_link.tsx | 2 +- .../side_panel/event_details/flyout/body.tsx | 6 +- .../event_details/flyout/footer.test.tsx | 19 +- .../event_details/flyout/footer.tsx | 7 +- .../event_details/flyout/header.tsx | 4 +- .../side_panel/event_details/helpers.tsx | 31 +- .../side_panel/event_details/index.test.tsx | 14 +- .../side_panel/event_details/index.tsx | 6 +- .../use_host_isolation_tools.tsx | 2 +- .../body/renderers/formatted_field.tsx | 6 +- .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - .../alert_details_right_panel.cy.ts | 8 +- 121 files changed, 2591 insertions(+), 2732 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/endpoint/service/host_isolation/utils.test.ts delete mode 100644 x-pack/plugins/security_solution/common/endpoint/service/host_isolation/utils.ts rename x-pack/plugins/security_solution/public/common/components/{ => endpoint}/agents/agent_status/agent_response_action_status.tsx (95%) rename x-pack/plugins/security_solution/public/common/components/{ => endpoint}/agents/agent_status/agent_status.test.tsx (93%) rename x-pack/plugins/security_solution/public/common/components/{ => endpoint}/agents/agent_status/agent_status.tsx (84%) rename x-pack/plugins/security_solution/public/common/components/{ => endpoint}/agents/agent_status/endpoint/endpoint_agent_status.test.tsx (92%) rename x-pack/plugins/security_solution/public/common/components/{ => endpoint}/agents/agent_status/endpoint/endpoint_agent_status.tsx (91%) rename x-pack/plugins/security_solution/public/common/components/{ => endpoint}/agents/agent_status/index.ts (100%) rename x-pack/plugins/security_solution/public/common/components/{ => endpoint}/agents/agent_status_text.ts (90%) rename x-pack/plugins/security_solution/public/{detections/components/endpoint_responder => common/components/endpoint/host_isolation/__mocks__}/index.ts (78%) create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/__mocks__/index.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/__mocks__/use_host_isolation_action.tsx rename x-pack/plugins/security_solution/public/{detections/components/host_isolation/index.test.tsx => common/components/endpoint/host_isolation/from_alerts/host_isolation_panel.test.tsx} (69%) create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/host_isolation_panel.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/index.ts rename x-pack/plugins/security_solution/public/{detections/components/host_isolation => common/components/endpoint/host_isolation/from_alerts}/isolate.tsx (85%) rename x-pack/plugins/security_solution/public/{detections/components/host_isolation => common/components/endpoint/host_isolation/from_alerts}/translations.ts (100%) rename x-pack/plugins/security_solution/public/{detections/components/host_isolation => common/components/endpoint/host_isolation/from_alerts}/unisolate.tsx (85%) rename x-pack/plugins/security_solution/public/{detections/containers/detection_engine/alerts => common/components/endpoint/host_isolation/from_alerts}/use_host_isolation.tsx (78%) create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.test.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.tsx rename x-pack/plugins/security_solution/public/{detections/containers/detection_engine/alerts => common/components/endpoint/host_isolation/from_alerts}/use_host_isolation_status.tsx (83%) rename x-pack/plugins/security_solution/public/{detections/containers/detection_engine/alerts => common/components/endpoint/host_isolation/from_alerts}/use_host_unisolation.tsx (77%) rename x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/{ => from_cases}/endpoint_host_isolation_cases_context.tsx (100%) create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_cases/index.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/index.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/responder/__mocks__/index.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/index.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/use_responder_action_data.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/use_responder_action_item.tsx create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/index.ts rename x-pack/plugins/security_solution/public/{detections/components/endpoint_responder => common/components/endpoint/responder/from_alerts}/responder_action_button.tsx (76%) rename x-pack/plugins/security_solution/public/{detections/components/endpoint_responder => common/components/endpoint/responder/from_alerts}/translations.ts (59%) create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.test.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_item.test.tsx rename x-pack/plugins/security_solution/public/{detections/components/endpoint_responder => common/components/endpoint/responder/from_alerts}/use_responder_action_item.tsx (52%) create mode 100644 x-pack/plugins/security_solution/public/common/components/endpoint/responder/index.ts create mode 100644 x-pack/plugins/security_solution/public/common/hooks/endpoint/__mocks__/use_alert_response_actions_support.ts create mode 100644 x-pack/plugins/security_solution/public/common/hooks/endpoint/use_alert_response_actions_support.test.ts create mode 100644 x-pack/plugins/security_solution/public/common/hooks/endpoint/use_alert_response_actions_support.ts rename x-pack/plugins/security_solution/public/common/lib/{ => endpoint}/endpoint_isolation/index.test.ts (91%) rename x-pack/plugins/security_solution/public/common/lib/{ => endpoint}/endpoint_isolation/index.ts (84%) rename x-pack/plugins/security_solution/public/common/lib/{ => endpoint}/endpoint_isolation/mocks.ts (81%) rename x-pack/plugins/security_solution/public/common/lib/{ => endpoint}/endpoint_pending_actions/endpoint_pending_actions.test.ts (88%) rename x-pack/plugins/security_solution/public/common/lib/{ => endpoint}/endpoint_pending_actions/endpoint_pending_actions.ts (77%) rename x-pack/plugins/security_solution/public/common/lib/{ => endpoint}/endpoint_pending_actions/index.ts (100%) rename x-pack/plugins/security_solution/public/common/lib/{ => endpoint}/endpoint_pending_actions/mocks.ts (82%) create mode 100644 x-pack/plugins/security_solution/public/common/lib/endpoint/index.ts rename x-pack/plugins/security_solution/public/{detections/components/host_isolation/helpers.ts => common/lib/endpoint/utils/get_event_details_field_values.ts} (64%) create mode 100644 x-pack/plugins/security_solution/public/common/lib/endpoint/utils/index.ts create mode 100644 x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_agent_type_and_action_supported.test.ts create mode 100644 x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_agent_type_and_action_supported.ts create mode 100644 x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_response_actions_alert_agent_id_field.ts create mode 100644 x-pack/plugins/security_solution/public/common/mock/endpoint/endpoint_alert_data_mock.ts delete mode 100644 x-pack/plugins/security_solution/public/common/utils/crowdstrike_alert_check.test.ts delete mode 100644 x-pack/plugins/security_solution/public/common/utils/crowdstrike_alert_check.ts delete mode 100644 x-pack/plugins/security_solution/public/common/utils/endpoint_alert_check.test.ts delete mode 100644 x-pack/plugins/security_solution/public/common/utils/endpoint_alert_check.ts delete mode 100644 x-pack/plugins/security_solution/public/common/utils/sentinelone_alert_check.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/endpoint_responder/get_external_edr_agent_info.test.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/endpoint_responder/get_external_edr_agent_info.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.test.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dad6ef851a1177..44c2a4f27636bb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1513,6 +1513,8 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/stack_connectors/public/connector_types/sentinelone @elastic/security-defend-workflows /x-pack/plugins/stack_connectors/server/connector_types/sentinelone @elastic/security-defend-workflows /x-pack/plugins/stack_connectors/common/sentinelone @elastic/security-defend-workflows +/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike @elastic/security-defend-workflows +/x-pack/plugins/stack_connectors/common/crowdstrike @elastic/security-defend-workflows ## Security Solution shared OAS schemas /x-pack/plugins/security_solution/common/api/model @elastic/security-detection-rule-management @elastic/security-detection-engine @@ -1596,12 +1598,14 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ ## Security Solution sub teams - security-defend-workflows /x-pack/plugins/security_solution/public/management/ @elastic/security-defend-workflows -/x-pack/plugins/security_solution/public/common/lib/endpoint*/ @elastic/security-defend-workflows -/x-pack/plugins/security_solution/public/common/components/agents/ @elastic/security-defend-workflows +/x-pack/plugins/security_solution/public/common/lib/endpoint/ @elastic/security-defend-workflows /x-pack/plugins/security_solution/public/common/components/endpoint/ @elastic/security-defend-workflows +/x-pack/plugins/security_solution/public/common/hooks/endpoint/ @elastic/security-defend-workflows +/x-pack/plugins/security_solution/public/common/mock/endpoint @elastic/security-defend-workflows +/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/ @elastic/security-defend-workflows /x-pack/plugins/security_solution/common/endpoint/ @elastic/security-defend-workflows -/x-pack/plugins/security_solution/server/endpoint/ @elastic/security-defend-workflows /x-pack/plugins/security_solution/common/api/endpoint/ @elastic/security-defend-workflows +/x-pack/plugins/security_solution/server/endpoint/ @elastic/security-defend-workflows /x-pack/plugins/security_solution/server/lists_integration/endpoint/ @elastic/security-defend-workflows /x-pack/plugins/security_solution/server/lib/license/ @elastic/security-defend-workflows /x-pack/plugins/security_solution/server/fleet_integration/ @elastic/security-defend-workflows @@ -1636,6 +1640,7 @@ x-pack/plugins/security_solution/common/api/entity_analytics @elastic/security-e x-pack/test/security_solution_api_integration/test_suites/genai @elastic/security-generative-ai # Security Defend Workflows - OSQuery Ownership +x-pack/plugins/osquery @elastic/security-defend-workflows /x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions @elastic/security-defend-workflows /x-pack/plugins/security_solution/public/detection_engine/rule_response_actions @elastic/security-defend-workflows /x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions @elastic/security-defend-workflows diff --git a/x-pack/plugins/security_solution/common/endpoint/service/host_isolation/utils.test.ts b/x-pack/plugins/security_solution/common/endpoint/service/host_isolation/utils.test.ts deleted file mode 100644 index 48928fb435fec2..00000000000000 --- a/x-pack/plugins/security_solution/common/endpoint/service/host_isolation/utils.test.ts +++ /dev/null @@ -1,84 +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 { isVersionSupported, isOsSupported, isIsolationSupported } from './utils'; - -describe('Host Isolation utils isVersionSupported', () => { - // NOTE: the `7.15.0.8295.0` and the text current versions are invalid. - test.each` - currentVersion | minVersionRequired | expected - ${'8.14.0'} | ${'7.13.0'} | ${true} - ${'7.14.0'} | ${'7.13.0'} | ${true} - ${'7.14.1'} | ${'7.14.0'} | ${true} - ${'8.14.0'} | ${'9.14.0'} | ${false} - ${'7.13.0'} | ${'7.14.0'} | ${false} - ${'7.14.0'} | ${'7.14.1'} | ${false} - ${'7.14.0'} | ${'7.14.0'} | ${true} - ${'7.14.0-SNAPSHOT'} | ${'7.14.0'} | ${true} - ${'7.14.0-SNAPSHOT-beta'} | ${'7.14.0'} | ${true} - ${'7.14.0-alpha'} | ${'7.14.0'} | ${true} - ${'8.0.0-SNAPSHOT'} | ${'7.14.0'} | ${true} - ${'8.0.0'} | ${'7.14.0'} | ${true} - ${'7.15.0.8295.0'} | ${'7.14.0'} | ${false} - ${'NOT_SEMVER'} | ${'7.14.0'} | ${false} - `( - 'should validate that version $a is compatible($expected) to $b', - ({ currentVersion, minVersionRequired, expected }) => { - expect( - isVersionSupported({ - currentVersion, - minVersionRequired, - }) - ).toEqual(expected); - } - ); -}); - -describe('Host Isolation utils isOsSupported', () => { - test.each` - currentOs | supportedOss | expected - ${'linux'} | ${{ macos: true, linux: true }} | ${true} - ${'linux'} | ${{ macos: true, windows: true }} | ${false} - `( - 'should validate that os $a is compatible($expected) to $b', - ({ currentOs, supportedOss, expected }) => { - expect( - isOsSupported({ - currentOs, - supportedOss, - }) - ).toEqual(expected); - } - ); -}); - -describe('Host Isolation utils isIsolationSupported', () => { - test.each` - osName | version | capabilities | expected - ${'windows'} | ${'7.14.0'} | ${[]} | ${true} - ${'linux'} | ${'7.13.0'} | ${['isolation']} | ${false} - ${'linux'} | ${'7.14.0'} | ${['isolation']} | ${false} - ${'macos'} | ${'7.13.0'} | ${['isolation']} | ${false} - ${'linux'} | ${'7.13.0'} | ${['isolation']} | ${false} - ${'windows'} | ${'7.15.0'} | ${[]} | ${false} - ${'macos'} | ${'7.15.0'} | ${[]} | ${false} - ${'linux'} | ${'7.15.0'} | ${['isolation']} | ${true} - ${'macos'} | ${'7.15.0'} | ${['isolation']} | ${true} - ${'linux'} | ${'7.16.0'} | ${['isolation']} | ${true} - `( - 'should validate that os $a, version $b, and capabilities $c supports hostIsolation($expected)', - ({ osName, version, capabilities, expected }) => { - expect( - isIsolationSupported({ - osName, - version, - capabilities, - }) - ).toEqual(expected); - } - ); -}); diff --git a/x-pack/plugins/security_solution/common/endpoint/service/host_isolation/utils.ts b/x-pack/plugins/security_solution/common/endpoint/service/host_isolation/utils.ts deleted file mode 100644 index 97d7eb2db641f5..00000000000000 --- a/x-pack/plugins/security_solution/common/endpoint/service/host_isolation/utils.ts +++ /dev/null @@ -1,83 +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 semverLte from 'semver/functions/lte'; -import type { ImmutableArray } from '../../types'; - -const minSupportedVersion = '7.14.0'; -const minCapabilitiesVersion = '7.15.0'; -const supportedOssMap = { - macos: true, - windows: true, -}; -const isolationCapability = 'isolation'; - -function parseSemver(semver: string) { - return semver.includes('-') ? semver.substring(0, semver.indexOf('-')) : semver; -} - -export const isVersionSupported = ({ - currentVersion, - minVersionRequired = minSupportedVersion, -}: { - currentVersion: string; - minVersionRequired?: string; -}) => { - // `parseSemver()` will throw if the version provided is not a valid semver value. - // If that happens, then just return false from this function - try { - const parsedCurrentVersion = parseSemver(currentVersion); - return semverLte(minVersionRequired, parsedCurrentVersion); - } catch (e) { - // If running in the browser, log to console - if (window && window.console) { - window.console.warn( - `SecuritySolution: isVersionSupported(): Unable to determine if current version [${currentVersion}] meets minimum version [${minVersionRequired}]. Error: ${e.message}` - ); - } - return false; - } -}; - -export const isOsSupported = ({ - currentOs, - supportedOss = supportedOssMap, -}: { - currentOs: string; - supportedOss?: { [os: string]: boolean }; -}) => !!supportedOss[currentOs]; - -function isCapabilitiesSupported(semver: string): boolean { - const parsedVersion = parseSemver(semver); - // capabilities is only available from 7.15+ - return semverLte(minCapabilitiesVersion, parsedVersion); -} - -function isIsolationSupportedCapabilities(capabilities: ImmutableArray = []): boolean { - return capabilities.includes(isolationCapability); -} - -// capabilities isn't introduced until 7.15 so check the OS for support -function isIsolationSupportedOS(osName: string): boolean { - const normalizedOs = osName.toLowerCase(); - return isOsSupported({ currentOs: normalizedOs }); -} - -export const isIsolationSupported = ({ - osName, - version, - capabilities, -}: { - osName: string; - version: string; - capabilities?: ImmutableArray; -}): boolean => { - if (!version || !isVersionSupported({ currentVersion: version })) return false; - - return isCapabilitiesSupported(version) - ? isIsolationSupportedCapabilities(capabilities) - : isIsolationSupportedOS(osName); -}; diff --git a/x-pack/plugins/security_solution/common/endpoint/service/response_actions/constants.ts b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/constants.ts index 32773a3fafef4f..fdfa5ed02cb73d 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/response_actions/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/constants.ts @@ -174,3 +174,14 @@ export const RESPONSE_ACTIONS_ZIP_PASSCODE: Readonly +> = Object.freeze({ + endpoint: 'agent.id', + sentinel_one: 'observer.serial_number', + crowdstrike: 'crowdstrike.event.DeviceId', +}); diff --git a/x-pack/plugins/security_solution/public/cases/pages/index.tsx b/x-pack/plugins/security_solution/public/cases/pages/index.tsx index e3eb2290e6e771..54ece0123738fb 100644 --- a/x-pack/plugins/security_solution/public/cases/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/pages/index.tsx @@ -10,6 +10,7 @@ import { useDispatch } from 'react-redux'; import type { CaseViewRefreshPropInterface } from '@kbn/cases-plugin/common'; import { CaseMetricsFeature } from '@kbn/cases-plugin/common'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { CaseDetailsRefreshContext } from '../../common/components/endpoint'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { DocumentDetailsRightPanelKey } from '../../flyout/document_details/shared/constants/panel_keys'; import { useTourContext } from '../../common/components/guided_onboarding_tour'; @@ -26,7 +27,6 @@ import { APP_ID, CASES_PATH, SecurityPageName } from '../../../common/constants' import { timelineActions } from '../../timelines/store'; import { useSourcererDataView } from '../../sourcerer/containers'; import { SourcererScopeName } from '../../sourcerer/store/model'; -import { CaseDetailsRefreshContext } from '../../common/components/endpoint/host_isolation/endpoint_host_isolation_cases_context'; import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper'; import { getEndpointDetailsPath } from '../../management/common/routing'; import { SpyRoute } from '../../common/utils/route/spy_routes'; diff --git a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_response_action_status.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/agent_response_action_status.tsx similarity index 95% rename from x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_response_action_status.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/agent_response_action_status.tsx index 72c3258a628635..275cc4751e6fe8 100644 --- a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_response_action_status.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/agent_response_action_status.tsx @@ -8,11 +8,11 @@ import React, { memo, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiTextColor, EuiToolTip } from '@elastic/eui'; -import type { EndpointPendingActions } from '../../../../../common/endpoint/types'; -import type { ResponseActionsApiCommandNames } from '../../../../../common/endpoint/service/response_actions/constants'; -import { RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP } from '../../../../../common/endpoint/service/response_actions/constants'; +import type { EndpointPendingActions } from '../../../../../../common/endpoint/types'; +import type { ResponseActionsApiCommandNames } from '../../../../../../common/endpoint/service/response_actions/constants'; +import { RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP } from '../../../../../../common/endpoint/service/response_actions/constants'; import { ISOLATED_LABEL, ISOLATING_LABEL, RELEASING_LABEL } from './endpoint/endpoint_agent_status'; -import { useTestIdGenerator } from '../../../../management/hooks/use_test_id_generator'; +import { useTestIdGenerator } from '../../../../../management/hooks/use_test_id_generator'; const TOOLTIP_CONTENT_STYLES: React.CSSProperties = Object.freeze({ width: 150 }); diff --git a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.test.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/agent_status.test.tsx similarity index 93% rename from x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.test.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/agent_status.test.tsx index 47210272781c00..b384cf9a542a24 100644 --- a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/agent_status.test.tsx @@ -11,17 +11,17 @@ import { AgentStatus } from './agent_status'; import { useAgentStatusHook, useGetAgentStatus, -} from '../../../../management/hooks/agents/use_get_agent_status'; +} from '../../../../../management/hooks/agents/use_get_agent_status'; import { RESPONSE_ACTION_AGENT_TYPE, type ResponseActionAgentType, -} from '../../../../../common/endpoint/service/response_actions/constants'; -import type { AppContextTestRender } from '../../../mock/endpoint'; -import { createAppRootMockRenderer } from '../../../mock/endpoint'; -import { HostStatus } from '../../../../../common/endpoint/types'; +} from '../../../../../../common/endpoint/service/response_actions/constants'; +import type { AppContextTestRender } from '../../../../mock/endpoint'; +import { createAppRootMockRenderer } from '../../../../mock/endpoint'; +import { HostStatus } from '../../../../../../common/endpoint/types'; -jest.mock('../../../hooks/use_experimental_features'); -jest.mock('../../../../management/hooks/agents/use_get_agent_status'); +jest.mock('../../../../hooks/use_experimental_features'); +jest.mock('../../../../../management/hooks/agents/use_get_agent_status'); const getAgentStatusMock = useGetAgentStatus as jest.Mock; const useAgentStatusHookMock = useAgentStatusHook as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/agent_status.tsx similarity index 84% rename from x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/agent_status.tsx index 363e233baab595..c4e61103e6a82f 100644 --- a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/agent_status.tsx @@ -8,12 +8,12 @@ import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React, { useMemo } from 'react'; import styled from 'styled-components'; -import type { ResponseActionAgentType } from '../../../../../common/endpoint/service/response_actions/constants'; -import type { EndpointPendingActions } from '../../../../../common/endpoint/types'; -import { useAgentStatusHook } from '../../../../management/hooks/agents/use_get_agent_status'; -import { useTestIdGenerator } from '../../../../management/hooks/use_test_id_generator'; -import { HOST_STATUS_TO_BADGE_COLOR } from '../../../../management/pages/endpoint_hosts/view/host_constants'; -import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import type { EndpointPendingActions } from '../../../../../../common/endpoint/types'; +import { useAgentStatusHook } from '../../../../../management/hooks/agents/use_get_agent_status'; +import { useTestIdGenerator } from '../../../../../management/hooks/use_test_id_generator'; +import { HOST_STATUS_TO_BADGE_COLOR } from '../../../../../management/pages/endpoint_hosts/view/host_constants'; +import { useIsExperimentalFeatureEnabled } from '../../../../hooks/use_experimental_features'; import { getAgentStatusText } from '../agent_status_text'; import { AgentResponseActionsStatus } from './agent_response_action_status'; export enum SENTINEL_ONE_NETWORK_STATUS { diff --git a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/endpoint/endpoint_agent_status.test.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/endpoint/endpoint_agent_status.test.tsx similarity index 92% rename from x-pack/plugins/security_solution/public/common/components/agents/agent_status/endpoint/endpoint_agent_status.test.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/endpoint/endpoint_agent_status.test.tsx index 58ef96a42b934b..40119d452d2c1a 100644 --- a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/endpoint/endpoint_agent_status.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/endpoint/endpoint_agent_status.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import type { AppContextTestRender } from '../../../../mock/endpoint'; -import { createAppRootMockRenderer } from '../../../../mock/endpoint'; +import type { AppContextTestRender } from '../../../../../mock/endpoint'; +import { createAppRootMockRenderer } from '../../../../../mock/endpoint'; import type { EndpointAgentStatusByIdProps, EndpointAgentStatusProps, @@ -15,18 +15,18 @@ import { EndpointAgentStatus, EndpointAgentStatusById } from './endpoint_agent_s import type { EndpointPendingActions, HostInfoInterface, -} from '../../../../../../common/endpoint/types'; -import { HostStatus } from '../../../../../../common/endpoint/types'; +} from '../../../../../../../common/endpoint/types'; +import { HostStatus } from '../../../../../../../common/endpoint/types'; import React from 'react'; -import { EndpointActionGenerator } from '../../../../../../common/endpoint/data_generators/endpoint_action_generator'; -import { EndpointDocGenerator } from '../../../../../../common/endpoint/generate_data'; -import { composeHttpHandlerMocks } from '../../../../mock/endpoint/http_handler_mock_factory'; -import type { EndpointMetadataHttpMocksInterface } from '../../../../../management/pages/endpoint_hosts/mocks'; -import { endpointMetadataHttpMocks } from '../../../../../management/pages/endpoint_hosts/mocks'; -import type { ResponseActionsHttpMocksInterface } from '../../../../../management/mocks/response_actions_http_mocks'; -import { responseActionsHttpMocks } from '../../../../../management/mocks/response_actions_http_mocks'; +import { EndpointActionGenerator } from '../../../../../../../common/endpoint/data_generators/endpoint_action_generator'; +import { EndpointDocGenerator } from '../../../../../../../common/endpoint/generate_data'; +import { composeHttpHandlerMocks } from '../../../../../mock/endpoint/http_handler_mock_factory'; +import type { EndpointMetadataHttpMocksInterface } from '../../../../../../management/pages/endpoint_hosts/mocks'; +import { endpointMetadataHttpMocks } from '../../../../../../management/pages/endpoint_hosts/mocks'; +import type { ResponseActionsHttpMocksInterface } from '../../../../../../management/mocks/response_actions_http_mocks'; +import { responseActionsHttpMocks } from '../../../../../../management/mocks/response_actions_http_mocks'; import { waitFor, within, fireEvent } from '@testing-library/react'; -import { getEmptyValue } from '../../../empty_value'; +import { getEmptyValue } from '../../../../empty_value'; import { clone, set } from 'lodash'; type AgentStatusApiMocksInterface = EndpointMetadataHttpMocksInterface & diff --git a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/endpoint/endpoint_agent_status.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/endpoint/endpoint_agent_status.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/common/components/agents/agent_status/endpoint/endpoint_agent_status.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/endpoint/endpoint_agent_status.tsx index 85568daa312b4b..a2b6d869f9d2df 100644 --- a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/endpoint/endpoint_agent_status.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/endpoint/endpoint_agent_status.tsx @@ -9,14 +9,14 @@ import React, { memo, useMemo } from 'react'; import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; -import { DEFAULT_POLL_INTERVAL } from '../../../../../management/common/constants'; -import { HOST_STATUS_TO_BADGE_COLOR } from '../../../../../management/pages/endpoint_hosts/view/host_constants'; -import { getEmptyValue } from '../../../empty_value'; - -import { useGetEndpointPendingActionsSummary } from '../../../../../management/hooks/response_actions/use_get_endpoint_pending_actions_summary'; -import { useTestIdGenerator } from '../../../../../management/hooks/use_test_id_generator'; -import type { EndpointPendingActions, HostInfo } from '../../../../../../common/endpoint/types'; -import { useGetEndpointDetails } from '../../../../../management/hooks'; +import { DEFAULT_POLL_INTERVAL } from '../../../../../../management/common/constants'; +import { HOST_STATUS_TO_BADGE_COLOR } from '../../../../../../management/pages/endpoint_hosts/view/host_constants'; +import { getEmptyValue } from '../../../../empty_value'; + +import { useGetEndpointPendingActionsSummary } from '../../../../../../management/hooks/response_actions/use_get_endpoint_pending_actions_summary'; +import { useTestIdGenerator } from '../../../../../../management/hooks/use_test_id_generator'; +import type { EndpointPendingActions, HostInfo } from '../../../../../../../common/endpoint/types'; +import { useGetEndpointDetails } from '../../../../../../management/hooks'; import { getAgentStatusText } from '../../agent_status_text'; import { AgentResponseActionsStatus } from '../agent_response_action_status'; diff --git a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/index.ts similarity index 100% rename from x-pack/plugins/security_solution/public/common/components/agents/agent_status/index.ts rename to x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status/index.ts diff --git a/x-pack/plugins/security_solution/public/common/components/agents/agent_status_text.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status_text.ts similarity index 90% rename from x-pack/plugins/security_solution/public/common/components/agents/agent_status_text.ts rename to x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status_text.ts index 45ffd9a90ce93d..ac0987e295283c 100644 --- a/x-pack/plugins/security_solution/public/common/components/agents/agent_status_text.ts +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/agents/agent_status_text.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import type { HostStatus } from '../../../../common/endpoint/types'; +import type { HostStatus } from '../../../../../common/endpoint/types'; export const getAgentStatusText = (hostStatus: HostStatus) => { return i18n.translate('xpack.securitySolution.endpoint.list.hostStatusValue', { diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/__mocks__/index.ts similarity index 78% rename from x-pack/plugins/security_solution/public/detections/components/endpoint_responder/index.ts rename to x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/__mocks__/index.ts index 5581755690e924..98e117c7017e05 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/__mocks__/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { useResponderActionItem } from './use_responder_action_item'; +export * from '../from_alerts/__mocks__'; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/__mocks__/index.ts new file mode 100644 index 00000000000000..033cb24d79ac32 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/__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 './use_host_isolation_action'; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/__mocks__/use_host_isolation_action.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/__mocks__/use_host_isolation_action.tsx new file mode 100644 index 00000000000000..6bbe386ff176d2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/__mocks__/use_host_isolation_action.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AlertTableContextMenuItem } from '../../../../../../detections/components/alerts_table/types'; +import { ISOLATE_HOST } from '../translations'; + +const useHostIsolationActionMock = (): AlertTableContextMenuItem[] => { + return [ + { + key: 'isolate-host-action-item', + 'data-test-subj': 'isolate-host-action-item', + disabled: false, + onClick: jest.fn(), + name: ISOLATE_HOST, + }, + ]; +}; + +export { useHostIsolationActionMock as useHostIsolationAction }; diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/host_isolation_panel.test.tsx similarity index 69% rename from x-pack/plugins/security_solution/public/detections/components/host_isolation/index.test.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/host_isolation_panel.test.tsx index 6a357e232a59d8..c3a37d9b031287 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/host_isolation_panel.test.tsx @@ -8,8 +8,10 @@ import React from 'react'; import { renderReactTestingLibraryWithI18n as render } from '@kbn/test-jest-helpers'; import { HostIsolationPanel } from '.'; -import { useKibana as mockUseKibana } from '../../../common/lib/kibana/__mocks__'; +import { useKibana as mockUseKibana } from '../../../../lib/kibana/__mocks__'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { endpointAlertDataMock } from '../../../../mock/endpoint'; +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; const queryClient = new QueryClient({ logger: { @@ -19,36 +21,40 @@ const queryClient = new QueryClient({ }, }); +jest.mock('../../../../experimental_features_service'); + const useKibanaMock = mockUseKibana as jest.Mock; -jest.mock('../../../common/lib/kibana'); +jest.mock('../../../../lib/kibana'); describe('HostIsolationPanel', () => { const renderWithContext = (Element: React.ReactElement) => render({Element}); + let cancelCallback: () => void; + let details: TimelineEventsDetailsItem[]; + beforeEach(() => { useKibanaMock.mockReturnValue({ ...mockUseKibana(), services: { ...mockUseKibana().services, notifications: { toasts: jest.fn() } }, }); + + cancelCallback = jest.fn(); + details = endpointAlertDataMock.generateEndpointAlertDetailsItemData(); }); - const details = [ - { - category: 'observer', - field: 'observer.serial_number', - values: ['expectedSentinelOneAgentId'], - originalValue: ['expectedSentinelOneAgentId'], - isObjectArray: false, - }, - { - category: 'crowdstrike', - field: 'crowdstrike.event.DeviceId', - values: ['expectedCrowdstrikeAgentId'], - originalValue: ['expectedCrowdstrikeAgentId'], - isObjectArray: false, - }, - ]; - const cancelCallback = jest.fn(); + it('should render warning callout if alert data host does not support response actions', () => { + const { getByTestId } = renderWithContext( + + ); + + expect(getByTestId('unsupportedAlertHost')).toHaveTextContent( + "The alert's host () does not support host isolation response actions." + ); + }); it('renders IsolateHost when isolateAction is "isolateHost"', () => { const { getByText } = renderWithContext( diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/host_isolation_panel.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/host_isolation_panel.tsx new file mode 100644 index 00000000000000..38e6ff1010d5c4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/host_isolation_panel.tsx @@ -0,0 +1,74 @@ +/* + * 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, { useMemo } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiCallOut } from '@elastic/eui'; +import { getAlertDetailsFieldValue } from '../../../../lib/endpoint/utils/get_event_details_field_values'; +import { useCasesFromAlerts } from '../../../../../detections/containers/detection_engine/alerts/use_cases_from_alerts'; +import type { TimelineEventsDetailsItem } from '../../../../../../common/search_strategy'; +import { IsolateHost } from './isolate'; +import { UnisolateHost } from './unisolate'; +import { useAlertResponseActionsSupport } from '../../../../hooks/endpoint/use_alert_response_actions_support'; + +export const HostIsolationPanel = React.memo( + ({ + details, + cancelCallback, + successCallback, + isolateAction, + }: { + details: TimelineEventsDetailsItem[] | null; + cancelCallback: () => void; + successCallback?: () => void; + isolateAction: string; + }) => { + const { + isSupported: alertHostSupportsResponseActions, + details: { agentId, agentType, hostName }, + } = useAlertResponseActionsSupport(details); + + const alertId = useMemo( + () => getAlertDetailsFieldValue({ category: '_id', field: '_id' }, details), + [details] + ); + + const { casesInfo } = useCasesFromAlerts({ alertId }); + + const formProps: React.ComponentProps & + React.ComponentProps = useMemo(() => { + return { + endpointId: agentId, + hostName, + casesInfo, + agentType, + cancelCallback, + successCallback, + }; + }, [agentId, agentType, cancelCallback, casesInfo, hostName, successCallback]); + + if (!alertHostSupportsResponseActions) { + return ( + + + + ); + } + + return isolateAction === 'isolateHost' ? ( + + ) : ( + + ); + } +); + +HostIsolationPanel.displayName = 'HostIsolationContent'; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/index.ts new file mode 100644 index 00000000000000..3ea62053d1ba9e --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/index.ts @@ -0,0 +1,10 @@ +/* + * 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 './host_isolation_panel'; +export * from './use_host_isolation_action'; +export * from './translations'; diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/isolate.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/isolate.tsx similarity index 85% rename from x-pack/plugins/security_solution/public/detections/components/host_isolation/isolate.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/isolate.tsx index 37fa3ad4bfccc2..df141abcba5e77 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/isolate.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/isolate.tsx @@ -8,15 +8,12 @@ import React, { useMemo, useState, useCallback } from 'react'; import { EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; -import { useHostIsolation } from '../../containers/detection_engine/alerts/use_host_isolation'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import { useHostIsolation } from './use_host_isolation'; import { CASES_ASSOCIATED_WITH_ALERT, RETURN_TO_ALERT_DETAILS } from './translations'; -import type { EndpointIsolatedFormProps } from '../../../common/components/endpoint/host_isolation'; -import { - EndpointIsolateForm, - ActionCompletionReturnButton, -} from '../../../common/components/endpoint/host_isolation'; -import type { CasesFromAlertsResponse } from '../../containers/detection_engine/alerts/types'; +import type { EndpointIsolatedFormProps } from '..'; +import { EndpointIsolateForm, ActionCompletionReturnButton } from '..'; +import type { CasesFromAlertsResponse } from '../../../../../detections/containers/detection_engine/alerts/types'; export const IsolateHost = React.memo( ({ diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/translations.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/components/host_isolation/translations.ts rename to x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/translations.ts diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/unisolate.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/unisolate.tsx similarity index 85% rename from x-pack/plugins/security_solution/public/detections/components/host_isolation/unisolate.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/unisolate.tsx index 15c59da521579d..171b0283a15c8e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/unisolate.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/unisolate.tsx @@ -8,15 +8,12 @@ import React, { useMemo, useState, useCallback } from 'react'; import { EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; import { CASES_ASSOCIATED_WITH_ALERT, RETURN_TO_ALERT_DETAILS } from './translations'; -import type { EndpointIsolatedFormProps } from '../../../common/components/endpoint/host_isolation'; -import { - EndpointUnisolateForm, - ActionCompletionReturnButton, -} from '../../../common/components/endpoint/host_isolation'; -import { useHostUnisolation } from '../../containers/detection_engine/alerts/use_host_unisolation'; -import type { CasesFromAlertsResponse } from '../../containers/detection_engine/alerts/types'; +import type { EndpointIsolatedFormProps } from '..'; +import { EndpointUnisolateForm, ActionCompletionReturnButton } from '..'; +import { useHostUnisolation } from './use_host_unisolation'; +import type { CasesFromAlertsResponse } from '../../../../../detections/containers/detection_engine/alerts/types'; export const UnisolateHost = React.memo( ({ diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation.tsx similarity index 78% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation.tsx index 85b2bea5d26958..6964ee1a343081 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation.tsx @@ -6,10 +6,10 @@ */ import { useCallback, useState } from 'react'; -import type { ResponseActionAgentType } from '../../../../../common/endpoint/service/response_actions/constants'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { HOST_ISOLATION_FAILURE } from './translations'; -import { createHostIsolation } from './api'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import { useAppToasts } from '../../../../hooks/use_app_toasts'; +import { HOST_ISOLATION_FAILURE } from '../../../../../detections/containers/detection_engine/alerts/translations'; +import { createHostIsolation } from '../../../../../detections/containers/detection_engine/alerts/api'; interface HostIsolationStatus { loading: boolean; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.test.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.test.tsx new file mode 100644 index 00000000000000..5c459286fe11b9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.test.tsx @@ -0,0 +1,144 @@ +/* + * 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 { FC, PropsWithChildren } from 'react'; +import React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import { useHostIsolationAction } from './use_host_isolation_action'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { + useAgentStatusHook, + useGetAgentStatus, + useGetSentinelOneAgentStatus, +} from '../../../../../management/hooks/agents/use_get_agent_status'; +import { useIsExperimentalFeatureEnabled } from '../../../../hooks/use_experimental_features'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import { ExperimentalFeaturesService as ExperimentalFeaturesServiceMock } from '../../../../experimental_features_service'; +import { endpointAlertDataMock } from '../../../../mock/endpoint'; + +jest.mock('../../../../../management/hooks/agents/use_get_agent_status'); +jest.mock('../../../../hooks/use_experimental_features'); +jest.mock('../../../../experimental_features_service'); + +const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; +const useGetSentinelOneAgentStatusMock = useGetSentinelOneAgentStatus as jest.Mock; +const useGetAgentStatusMock = useGetAgentStatus as jest.Mock; +const useAgentStatusHookMock = useAgentStatusHook as jest.Mock; + +describe('useHostIsolationAction', () => { + const setFeatureFlags = (isEnabled: boolean = true): void => { + useIsExperimentalFeatureEnabledMock.mockReturnValue(isEnabled); + (ExperimentalFeaturesServiceMock.get as jest.Mock).mockReturnValue({ + responseActionsSentinelOneV1Enabled: isEnabled, + responseActionsCrowdstrikeManualHostIsolationEnabled: isEnabled, + }); + }; + + const createReactQueryWrapper = () => { + const queryClient = new QueryClient(); + const wrapper: FC> = ({ children }) => ( + {children} + ); + return wrapper; + }; + + it('should NOT return the menu item for Events', () => { + useAgentStatusHookMock.mockImplementation(() => { + return jest.fn(() => { + return { data: {} }; + }); + }); + setFeatureFlags(true); + const { result } = renderHook( + () => { + return useHostIsolationAction({ + closePopover: jest.fn(), + detailsData: endpointAlertDataMock.generateAlertDetailsItemDataForAgentType('foo', { + 'kibana.alert.rule.uuid': undefined, + }), + isHostIsolationPanelOpen: false, + onAddIsolationStatusClick: jest.fn(), + }); + }, + { wrapper: createReactQueryWrapper() } + ); + + expect(result.current).toHaveLength(0); + }); + + // FIXME:PT refactor describe below - its not actually testing the component! Tests seem to be for `useAgentStatusHook()` + describe.each([ + ['useGetSentinelOneAgentStatus', useGetSentinelOneAgentStatusMock], + ['useGetAgentStatus', useGetAgentStatusMock], + ])('works with %s hook', (name, hook) => { + const render = (agentTypeAlert: ResponseActionAgentType) => + renderHook( + () => + useHostIsolationAction({ + closePopover: jest.fn(), + detailsData: + endpointAlertDataMock.generateAlertDetailsItemDataForAgentType(agentTypeAlert), + isHostIsolationPanelOpen: false, + onAddIsolationStatusClick: jest.fn(), + }), + { + wrapper: createReactQueryWrapper(), + } + ); + + beforeEach(() => { + useAgentStatusHookMock.mockImplementation(() => hook); + setFeatureFlags(true); + }); + + afterEach(() => { + jest.clearAllMocks(); + (ExperimentalFeaturesServiceMock.get as jest.Mock).mockReset(); + }); + + it(`${name} is invoked as 'enabled' when SentinelOne alert and FF enabled`, () => { + render('sentinel_one'); + + expect(hook).toHaveBeenCalledWith(['abfe4a35-d5b4-42a0-a539-bd054c791769'], 'sentinel_one', { + enabled: true, + }); + }); + it(`${name} is invoked as 'enabled' when Crowdstrike alert and FF enabled`, () => { + render('crowdstrike'); + + expect(hook).toHaveBeenCalledWith(['abfe4a35-d5b4-42a0-a539-bd054c791769'], 'crowdstrike', { + enabled: true, + }); + }); + + it(`${name} is invoked as 'disabled' when SentinelOne alert and FF disabled`, () => { + setFeatureFlags(false); + render('sentinel_one'); + + expect(hook).toHaveBeenCalledWith(['abfe4a35-d5b4-42a0-a539-bd054c791769'], 'sentinel_one', { + enabled: false, + }); + }); + + it(`${name} is invoked as 'disabled' when Crowdstrike alert and FF disabled`, () => { + setFeatureFlags(false); + render('crowdstrike'); + + expect(hook).toHaveBeenCalledWith(['abfe4a35-d5b4-42a0-a539-bd054c791769'], 'crowdstrike', { + enabled: false, + }); + }); + + it(`${name} is invoked as 'disabled' when endpoint alert`, () => { + render('endpoint'); + + expect(hook).toHaveBeenCalledWith(['abfe4a35-d5b4-42a0-a539-bd054c791769'], 'endpoint', { + enabled: false, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.tsx new file mode 100644 index 00000000000000..42f31ba9468875 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.tsx @@ -0,0 +1,175 @@ +/* + * 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 { useCallback, useMemo } from 'react'; +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { + HOST_ENDPOINT_UNENROLLED_TOOLTIP, + LOADING_ENDPOINT_DATA_TOOLTIP, + NOT_FROM_ENDPOINT_HOST_TOOLTIP, +} from '../../responder'; +import { useAlertResponseActionsSupport } from '../../../../hooks/endpoint/use_alert_response_actions_support'; +import { useIsExperimentalFeatureEnabled } from '../../../../hooks/use_experimental_features'; +import type { AgentStatusInfo } from '../../../../../../common/endpoint/types'; +import { HostStatus } from '../../../../../../common/endpoint/types'; +import { useEndpointHostIsolationStatus } from './use_host_isolation_status'; +import { ISOLATE_HOST, UNISOLATE_HOST } from './translations'; +import { useUserPrivileges } from '../../../user_privileges'; +import type { AlertTableContextMenuItem } from '../../../../../detections/components/alerts_table/types'; +import { useAgentStatusHook } from '../../../../../management/hooks/agents/use_get_agent_status'; + +interface UseHostIsolationActionProps { + closePopover: () => void; + detailsData: TimelineEventsDetailsItem[] | null; + isHostIsolationPanelOpen: boolean; + onAddIsolationStatusClick: (action: 'isolateHost' | 'unisolateHost') => void; +} + +export const useHostIsolationAction = ({ + closePopover, + detailsData, + isHostIsolationPanelOpen, + onAddIsolationStatusClick, +}: UseHostIsolationActionProps): AlertTableContextMenuItem[] => { + const { + isSupported: hostSupportsResponseActions, + isAlert, + unsupportedReason, + details: { + agentType, + agentId, + agentSupport: { isolate: isolationSupported }, + }, + } = useAlertResponseActionsSupport(detailsData); + const agentStatusClientEnabled = useIsExperimentalFeatureEnabled('agentStatusClientEnabled'); + const useAgentStatus = useAgentStatusHook(); + const { canIsolateHost, canUnIsolateHost } = useUserPrivileges().endpointPrivileges; + + const isEndpointAgent = useMemo(() => { + return agentType === 'endpoint'; + }, [agentType]); + + const { + loading: loadingHostIsolationStatus, + isIsolated, + agentStatus, + capabilities, + } = useEndpointHostIsolationStatus({ + agentId, + agentType, + }); + + const { data: externalAgentData } = useAgentStatus([agentId], agentType, { + enabled: hostSupportsResponseActions && !isEndpointAgent, + }); + + const externalAgentStatus = externalAgentData?.[agentId]; + + const isHostIsolated = useMemo((): boolean => { + if (!isEndpointAgent) { + return Boolean(externalAgentStatus?.isolated); + } + + return isIsolated; + }, [isEndpointAgent, isIsolated, externalAgentStatus?.isolated]); + + const doesHostSupportIsolation = useMemo(() => { + // With Elastic Defend Endpoint, we check that the actual `endpoint` agent on + // this host reported that capability + if (agentType === 'endpoint') { + return capabilities.includes('isolation'); + } + + return Boolean(externalAgentStatus?.found && isolationSupported); + }, [agentType, externalAgentStatus?.found, isolationSupported, capabilities]); + + const isolateHostHandler = useCallback(() => { + closePopover(); + if (!isHostIsolated) { + onAddIsolationStatusClick('isolateHost'); + } else { + onAddIsolationStatusClick('unisolateHost'); + } + }, [closePopover, isHostIsolated, onAddIsolationStatusClick]); + + const isHostAgentUnEnrolled = useMemo(() => { + if (!hostSupportsResponseActions) { + return true; + } + + if (isEndpointAgent) { + return agentStatus === HostStatus.UNENROLLED; + } + + // NON-Endpoint agent types + // 8.15 use FF for computing if action is enabled + if (agentStatusClientEnabled) { + return externalAgentStatus?.status === HostStatus.UNENROLLED; + } + + // else use the old way + if (!externalAgentStatus) { + return true; + } + + const { isUninstalled, isPendingUninstall } = externalAgentStatus as AgentStatusInfo[string]; + + return isUninstalled || isPendingUninstall; + }, [ + hostSupportsResponseActions, + isEndpointAgent, + agentStatusClientEnabled, + externalAgentStatus, + agentStatus, + ]); + + return useMemo(() => { + // If not an Alert OR user has no Authz, then don't show the menu item at all + if (!isAlert || (isHostIsolated && !canUnIsolateHost) || !canIsolateHost) { + return []; + } + + const menuItem: AlertTableContextMenuItem = { + key: 'isolate-host-action-item', + 'data-test-subj': 'isolate-host-action-item', + disabled: isHostAgentUnEnrolled || isHostIsolationPanelOpen, + onClick: isolateHostHandler, + name: isHostIsolated ? UNISOLATE_HOST : ISOLATE_HOST, + }; + + // Determine if menu item should be disabled + if (!doesHostSupportIsolation) { + menuItem.disabled = true; + // If we were able to calculate the agentType and we have a reason why the host is does not + // support response actions, then show that as the tooltip. Else, just show the normal "enroll" message + menuItem.toolTipContent = + agentType && unsupportedReason ? unsupportedReason : NOT_FROM_ENDPOINT_HOST_TOOLTIP; + } else if (isEndpointAgent && loadingHostIsolationStatus) { + menuItem.disabled = true; + menuItem.toolTipContent = LOADING_ENDPOINT_DATA_TOOLTIP; + } else if (isHostAgentUnEnrolled) { + menuItem.disabled = true; + menuItem.toolTipContent = isEndpointAgent + ? HOST_ENDPOINT_UNENROLLED_TOOLTIP + : NOT_FROM_ENDPOINT_HOST_TOOLTIP; + } + + return [menuItem]; + }, [ + isAlert, + isHostIsolated, + canUnIsolateHost, + canIsolateHost, + isHostAgentUnEnrolled, + isHostIsolationPanelOpen, + isolateHostHandler, + doesHostSupportIsolation, + isEndpointAgent, + loadingHostIsolationStatus, + agentType, + unsupportedReason, + ]); +}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation_status.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_status.tsx similarity index 83% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation_status.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_status.tsx index 0646a9904e9390..825cff88ab95ed 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_isolation_status.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_status.tsx @@ -7,11 +7,11 @@ import { isEmpty } from 'lodash'; import { useEffect, useState } from 'react'; -import type { ResponseActionAgentType } from '../../../../../common/endpoint/service/response_actions/constants'; -import { getHostMetadata } from './api'; -import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions'; -import { isEndpointHostIsolated } from '../../../../common/utils/validators'; -import { HostStatus } from '../../../../../common/endpoint/types'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import { getHostMetadata } from '../../../../../detections/containers/detection_engine/alerts/api'; +import { fetchPendingActionsByAgentId } from '../../../../lib/endpoint/endpoint_pending_actions'; +import { isEndpointHostIsolated } from '../../../../utils/validators'; +import { HostStatus } from '../../../../../../common/endpoint/types'; interface HostIsolationStatusResponse { loading: boolean; @@ -22,8 +22,9 @@ interface HostIsolationStatusResponse { pendingUnisolation: number; } -/* - * Retrieves the current isolation status of a host and the agent/host status */ +/** + * Retrieves the current isolation status of a host and the agent/host status + */ export const useEndpointHostIsolationStatus = ({ agentId, agentType, @@ -79,16 +80,15 @@ export const useEndpointHostIsolationStatus = ({ } } catch (error) { // silently catch non-user initiated error - return; - } - - if (isMounted) { - setLoading(false); } }; if (!isEmpty(agentId) && agentType === 'endpoint') { - fetchData(); + fetchData().finally(() => { + if (isMounted) { + setLoading(false); + } + }); } return () => { // updates to show component is unmounted diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_unisolation.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_unisolation.tsx similarity index 77% rename from x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_unisolation.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_unisolation.tsx index 47c09186f7cbae..1cd0d7fe3b886e 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_host_unisolation.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_unisolation.tsx @@ -6,10 +6,10 @@ */ import { useCallback, useState } from 'react'; -import type { ResponseActionAgentType } from '../../../../../common/endpoint/service/response_actions/constants'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { HOST_ISOLATION_FAILURE } from './translations'; -import { createHostUnIsolation } from './api'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import { useAppToasts } from '../../../../hooks/use_app_toasts'; +import { HOST_ISOLATION_FAILURE } from '../../../../../detections/containers/detection_engine/alerts/translations'; +import { createHostUnIsolation } from '../../../../../detections/containers/detection_engine/alerts/api'; interface HostUnisolationStatus { loading: boolean; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/endpoint_host_isolation_cases_context.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_cases/endpoint_host_isolation_cases_context.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/endpoint_host_isolation_cases_context.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_cases/endpoint_host_isolation_cases_context.tsx diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_cases/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_cases/index.ts new file mode 100644 index 00000000000000..930e3d362683ad --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_cases/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 './endpoint_host_isolation_cases_context'; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/index.ts index 41763a6e88d372..077bb416c800f8 100644 --- a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/index.ts @@ -9,3 +9,5 @@ export * from './isolate_success'; export * from './isolate_form'; export * from './unisolate_form'; export * from './action_completion_return_button'; +export * from './from_alerts'; +export * from './from_cases'; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/index.ts new file mode 100644 index 00000000000000..49ad6c8bfd9d20 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/index.ts @@ -0,0 +1,11 @@ +/* + * 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 './host_isolation'; +export * from './responder'; +export * from './link_to_app'; +export * from './route_capture'; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/__mocks__/index.ts new file mode 100644 index 00000000000000..98e117c7017e05 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/__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 '../from_alerts/__mocks__'; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/index.ts new file mode 100644 index 00000000000000..9f070ce76a53dd --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './use_responder_action_data'; +export * from './use_responder_action_item'; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/use_responder_action_data.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/use_responder_action_data.ts new file mode 100644 index 00000000000000..c84c5ea9dafbd6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/use_responder_action_data.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ResponderActionData, UseWithResponderActionDataFromAlertProps } from '../../..'; + +const useWithResponderActionDataFromAlertMock = ( + options: UseWithResponderActionDataFromAlertProps +): ResponderActionData => { + return { + handleResponseActionsClick: jest.fn(() => { + if (options.onClick) { + options.onClick(); + } + }), + isDisabled: false, + tooltip: null, + }; +}; + +export { useWithResponderActionDataFromAlertMock as useWithResponderActionDataFromAlert }; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/use_responder_action_item.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/use_responder_action_item.tsx new file mode 100644 index 00000000000000..bdeed284fa5ed9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/__mocks__/use_responder_action_item.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AlertTableContextMenuItem } from '../../../../../../detections/components/alerts_table/types'; + +const useResponderActionItemMock = (): AlertTableContextMenuItem[] => { + return [ + { + key: 'endpointResponseActions-action-item', + 'data-test-subj': 'endpointResponseActions-action-item', + disabled: false, + toolTipContent: undefined, + size: 's', + onClick: jest.fn(), + name: 'Respond', + }, + ]; +}; + +export { useResponderActionItemMock as useResponderActionItem }; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/index.ts new file mode 100644 index 00000000000000..2f39f582e93fc9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/index.ts @@ -0,0 +1,11 @@ +/* + * 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 './responder_action_button'; +export * from './use_responder_action_item'; +export * from './use_responder_action_data'; +export * from './translations'; diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_action_button.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/responder_action_button.tsx similarity index 76% rename from x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_action_button.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/responder_action_button.tsx index cb5876f27dd671..5d3aba47c21844 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_action_button.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/responder_action_button.tsx @@ -8,18 +8,15 @@ import { EuiButton, EuiToolTip } from '@elastic/eui'; import React, { memo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { - type ResponderContextMenuItemProps, - useResponderActionData, -} from './use_responder_action_data'; -import { useUserPrivileges } from '../../../common/components/user_privileges'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import { useResponderActionData } from './use_responder_action_data'; +import { useUserPrivileges } from '../../../user_privileges'; -export const ResponderActionButton = memo( - ({ agentType, endpointId, onClick }) => { +export const ResponderActionButton = memo<{ agentId: string; agentType: ResponseActionAgentType }>( + ({ agentType, agentId }) => { const { handleResponseActionsClick, isDisabled, tooltip } = useResponderActionData({ agentType, - endpointId, - onClick, + agentId, }); const endpointPrivileges = useUserPrivileges().endpointPrivileges; diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/translations.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/translations.ts similarity index 59% rename from x-pack/plugins/security_solution/public/detections/components/endpoint_responder/translations.ts rename to x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/translations.ts index 52dd93cc5c7cc1..3df858b9673f1b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/translations.ts @@ -6,8 +6,6 @@ */ import { i18n } from '@kbn/i18n'; -import { CROWDSTRIKE_AGENT_ID_FIELD } from '../../../common/utils/crowdstrike_alert_check'; -import { SENTINEL_ONE_AGENT_ID_FIELD } from '../../../common/utils/sentinelone_alert_check'; export const NOT_FROM_ENDPOINT_HOST_TOOLTIP = i18n.translate( 'xpack.securitySolution.endpoint.detections.takeAction.responseActionConsole.notSupportedTooltip', @@ -27,22 +25,3 @@ export const METADATA_API_ERROR_TOOLTIP = i18n.translate( 'xpack.securitySolution.endpoint.detections.takeAction.responseActionConsole.generalMetadataErrorTooltip', { defaultMessage: 'Failed to retrieve Endpoint metadata' } ); - -export const SENTINEL_ONE_AGENT_ID_PROPERTY_MISSING = i18n.translate( - 'xpack.securitySolution.endpoint.detections.takeAction.responseActionConsole.missingSentinelOneAgentId', - { - defaultMessage: 'Event data missing SentinelOne agent identifier ({field})', - values: { - field: SENTINEL_ONE_AGENT_ID_FIELD, - }, - } -); -export const CROWDSTRIKE_AGENT_ID_PROPERTY_MISSING = i18n.translate( - 'xpack.securitySolution.endpoint.detections.takeAction.responseActionConsole.missingCrowdstrikeAgentId', - { - defaultMessage: 'Event data missing Crowdstrike agent identifier ({field})', - values: { - field: CROWDSTRIKE_AGENT_ID_FIELD, - }, - } -); diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.test.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.test.ts new file mode 100644 index 00000000000000..89ad874726d91d --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.test.ts @@ -0,0 +1,283 @@ +/* + * 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 { + UseWithResponderActionDataFromAlertProps, + ResponderActionData, + UseResponderActionDataProps, +} from './use_responder_action_data'; +import { + useResponderActionData, + useWithResponderActionDataFromAlert, +} from './use_responder_action_data'; +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { + HOST_ENDPOINT_UNENROLLED_TOOLTIP, + LOADING_ENDPOINT_DATA_TOOLTIP, + METADATA_API_ERROR_TOOLTIP, + NOT_FROM_ENDPOINT_HOST_TOOLTIP, +} from './translations'; +import type { AppContextTestRender } from '../../../../mock/endpoint'; +import { createAppRootMockRenderer, endpointAlertDataMock } from '../../../../mock/endpoint'; +import { HOST_METADATA_LIST_ROUTE } from '../../../../../../common/endpoint/constants'; +import { endpointMetadataHttpMocks } from '../../../../../management/pages/endpoint_hosts/mocks'; +import type { RenderHookResult } from '@testing-library/react-hooks/src/types'; +import { createHttpFetchError } from '@kbn/core-http-browser-mocks'; +import { HostStatus } from '../../../../../../common/endpoint/types'; +import { + RESPONSE_ACTION_AGENT_TYPE, + RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD, +} from '../../../../../../common/endpoint/service/response_actions/constants'; +import { getAgentTypeName } from '../../../../translations'; +import { ALERT_EVENT_DATA_MISSING_AGENT_ID_FIELD } from '../../../../hooks/endpoint/use_alert_response_actions_support'; + +describe('use responder action data hooks', () => { + let appContextMock: AppContextTestRender; + let onClickMock: UseWithResponderActionDataFromAlertProps['onClick']; + + const getExpectedResponderActionData = ( + overrides: Partial = {} + ): ResponderActionData => { + return { + isDisabled: false, + tooltip: undefined, + handleResponseActionsClick: expect.any(Function), + ...overrides, + }; + }; + + beforeEach(() => { + appContextMock = createAppRootMockRenderer(); + onClickMock = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('useWithResponderActionDataFromAlert() hook', () => { + let renderHook: () => RenderHookResult< + UseWithResponderActionDataFromAlertProps, + ResponderActionData + >; + let alertDetailItemData: TimelineEventsDetailsItem[]; + + beforeEach(() => { + renderHook = () => { + return appContextMock.renderHook< + UseWithResponderActionDataFromAlertProps, + ResponderActionData + >(() => + useWithResponderActionDataFromAlert({ + eventData: alertDetailItemData, + onClick: onClickMock, + }) + ); + }; + }); + + describe('Common behaviours', () => { + it('should show action as disabled if agent does not support response actions', () => { + alertDetailItemData = endpointAlertDataMock.generateAlertDetailsItemDataForAgentType('foo'); + + expect(renderHook().result.current).toEqual( + getExpectedResponderActionData({ + isDisabled: true, + tooltip: NOT_FROM_ENDPOINT_HOST_TOOLTIP, + }) + ); + }); + + it('should call `onClick()` function prop when is pass to the hook', () => { + alertDetailItemData = endpointAlertDataMock.generateSentinelOneAlertDetailsItemData(); + const { result } = renderHook(); + result.current.handleResponseActionsClick(); + + expect(onClickMock).toHaveBeenCalled(); + }); + + it('should NOT call `onClick` if the action is disabled', () => { + alertDetailItemData = endpointAlertDataMock.generateAlertDetailsItemDataForAgentType('foo'); + const { result } = renderHook(); + result.current.handleResponseActionsClick(); + + expect(onClickMock).not.toHaveBeenCalled(); + }); + }); + + describe('and agentType is NOT Endpoint', () => { + beforeEach(() => { + alertDetailItemData = endpointAlertDataMock.generateSentinelOneAlertDetailsItemData(); + }); + + it('should show action when agentType is supported', () => { + expect(renderHook().result.current).toEqual(getExpectedResponderActionData()); + }); + + it('should NOT call the endpoint host metadata api', () => { + renderHook(); + const wasMetadataApiCalled = appContextMock.coreStart.http.get.mock.calls.some(([path]) => { + return (path as unknown as string).includes(HOST_METADATA_LIST_ROUTE); + }); + + expect(wasMetadataApiCalled).toBe(false); + }); + + it.each([...RESPONSE_ACTION_AGENT_TYPE])( + 'should show action disabled with tooltip for %s if agent id field is missing', + (agentType) => { + alertDetailItemData = endpointAlertDataMock.generateAlertDetailsItemDataForAgentType( + agentType, + { + [RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD[agentType]]: undefined, + } + ); + + expect(renderHook().result.current).toEqual( + getExpectedResponderActionData({ + isDisabled: true, + tooltip: ALERT_EVENT_DATA_MISSING_AGENT_ID_FIELD( + getAgentTypeName(agentType), + RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD[agentType] + ), + }) + ); + } + ); + }); + + describe('and agentType IS Endpoint', () => { + let metadataApiMocks: ReturnType; + + beforeEach(() => { + alertDetailItemData = endpointAlertDataMock.generateEndpointAlertDetailsItemData(); + metadataApiMocks = endpointMetadataHttpMocks(appContextMock.coreStart.http); + }); + + it('should show action disabled with tooltip while retrieving host metadata', () => { + expect(renderHook().result.current).toEqual( + getExpectedResponderActionData({ + isDisabled: true, + tooltip: LOADING_ENDPOINT_DATA_TOOLTIP, + }) + ); + }); + + it('should show action enabled if host metadata was retrieved and host is enrolled', async () => { + const { result, waitForValueToChange } = renderHook(); + await waitForValueToChange(() => result.current.isDisabled); + + expect(result.current).toEqual(getExpectedResponderActionData()); + }); + + it('should show action disabled if host was not found', async () => { + metadataApiMocks.responseProvider.metadataDetails.mockImplementation(() => { + throw createHttpFetchError('Not found', undefined, undefined, undefined, { + statusCode: 404, + }); + }); + const { result, waitForValueToChange } = renderHook(); + await waitForValueToChange(() => result.current.tooltip); + + expect(result.current).toEqual( + getExpectedResponderActionData({ + isDisabled: true, + tooltip: NOT_FROM_ENDPOINT_HOST_TOOLTIP, + }) + ); + }); + + it('should show action as disabled with tooltip when host is found, but has a status of unenrolled', async () => { + const hostMetadata = { + ...metadataApiMocks.responseProvider.metadataDetails(), + host_status: HostStatus.UNENROLLED, + }; + metadataApiMocks.responseProvider.metadataDetails.mockReturnValue(hostMetadata); + + const { result, waitForValueToChange } = renderHook(); + await waitForValueToChange(() => result.current.tooltip); + + expect(result.current).toEqual( + getExpectedResponderActionData({ + isDisabled: true, + tooltip: HOST_ENDPOINT_UNENROLLED_TOOLTIP, + }) + ); + }); + + it('should show action disabled if a metadata API error was encountered', async () => { + metadataApiMocks.responseProvider.metadataDetails.mockImplementation(() => { + throw createHttpFetchError('Server error', undefined, undefined, undefined, { + statusCode: 500, + }); + }); + const { result, waitForValueToChange } = renderHook(); + await waitForValueToChange(() => result.current.tooltip); + + expect(result.current).toEqual( + getExpectedResponderActionData({ + isDisabled: true, + tooltip: METADATA_API_ERROR_TOOLTIP, + }) + ); + }); + }); + }); + + describe('useResponderActionData() hook', () => { + let hookProps: UseResponderActionDataProps; + let renderHook: () => RenderHookResult; + + beforeEach(() => { + endpointMetadataHttpMocks(appContextMock.coreStart.http); + hookProps = { + agentId: 'agent-123', + agentType: 'endpoint', + onClick: onClickMock, + }; + renderHook = () => { + return appContextMock.renderHook(() => + useResponderActionData(hookProps) + ); + }; + }); + + it('should show action enabled when agentType is Endpoint and host is enabled', async () => { + const { result, waitForValueToChange } = renderHook(); + await waitForValueToChange(() => result.current.isDisabled); + + expect(result.current).toEqual(getExpectedResponderActionData()); + }); + + it('should show action disabled if agent type is not Endpoint', () => { + hookProps.agentType = 'crowdstrike'; + + expect(renderHook().result.current).toEqual( + getExpectedResponderActionData({ + isDisabled: true, + tooltip: NOT_FROM_ENDPOINT_HOST_TOOLTIP, + }) + ); + }); + + it('should call `onClick` prop when action is enabled', async () => { + const { result, waitForValueToChange } = renderHook(); + await waitForValueToChange(() => result.current.isDisabled); + result.current.handleResponseActionsClick(); + + expect(onClickMock).toHaveBeenCalled(); + }); + + it('should not call `onCLick` prop when action is disabled', () => { + hookProps.agentType = 'sentinel_one'; + const { result } = renderHook(); + result.current.handleResponseActionsClick(); + + expect(onClickMock).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.ts new file mode 100644 index 00000000000000..266425dd452dab --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.ts @@ -0,0 +1,271 @@ +/* + * 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 { ReactNode } from 'react'; +import { useCallback, useMemo } from 'react'; +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { useAlertResponseActionsSupport } from '../../../../hooks/endpoint/use_alert_response_actions_support'; +import type { + EndpointCapabilities, + ResponseActionAgentType, +} from '../../../../../../common/endpoint/service/response_actions/constants'; +import { useGetEndpointDetails, useWithShowResponder } from '../../../../../management/hooks'; +import { HostStatus } from '../../../../../../common/endpoint/types'; +import { + HOST_ENDPOINT_UNENROLLED_TOOLTIP, + LOADING_ENDPOINT_DATA_TOOLTIP, + METADATA_API_ERROR_TOOLTIP, + NOT_FROM_ENDPOINT_HOST_TOOLTIP, +} from './translations'; + +export interface UseWithResponderActionDataFromAlertProps { + eventData: TimelineEventsDetailsItem[] | null; + onClick?: () => void; +} + +export interface ResponderActionData { + handleResponseActionsClick: () => void; + isDisabled: boolean; + tooltip: ReactNode; +} + +/** + * This hook is used to get the data needed to show the context menu items for the responder + * actions using Alert data. + * + * NOTE: If wanting to get teh same type of response but don't have Alert + * data, use `useResponderActionData()` instead + * + * @param onClick the callback to handle the click event + * @param eventData the event data, exists only when agentType !== 'endpoint' + * @returns an object with the data needed to show the context menu item + */ +export const useWithResponderActionDataFromAlert = ({ + eventData = [], + onClick, +}: UseWithResponderActionDataFromAlertProps): ResponderActionData => { + const { + isSupported: hostSupportsResponseActions, + unsupportedReason, + details: { agentType, agentId, platform, hostName }, + } = useAlertResponseActionsSupport(eventData); + + const isEndpointHost = agentType === 'endpoint'; + + const endpointHostData = useResponderDataForEndpointHost( + agentId, + hostSupportsResponseActions && isEndpointHost + ); + const showResponseActionsConsole = useWithShowResponder(); + + const [isDisabled, tooltip]: [disabled: boolean, tooltip: ReactNode] = useMemo(() => { + if (!hostSupportsResponseActions) { + return [ + true, + agentType && unsupportedReason ? unsupportedReason : NOT_FROM_ENDPOINT_HOST_TOOLTIP, + ]; + } + + if (isEndpointHost) { + return [endpointHostData.isDisabled, endpointHostData.tooltip]; + } + + return [false, undefined]; + }, [ + hostSupportsResponseActions, + isEndpointHost, + agentType, + unsupportedReason, + endpointHostData.isDisabled, + endpointHostData.tooltip, + ]); + + const handleResponseActionsClick = useCallback(() => { + if (!isDisabled) { + showResponseActionsConsole({ + agentId, + agentType, + hostName, + platform, + capabilities: isEndpointHost ? endpointHostData.capabilities : [], + }); + + if (onClick) { + onClick(); + } + } + }, [ + isDisabled, + showResponseActionsConsole, + agentId, + agentType, + hostName, + platform, + isEndpointHost, + endpointHostData.capabilities, + onClick, + ]); + + return { + handleResponseActionsClick, + isDisabled, + tooltip, + }; +}; + +type ResponderDataForEndpointHost = Omit & { + capabilities: EndpointCapabilities[]; + hostName: string; + platform: string; +}; + +/** + * Hook to specifically for the responder data for Elastic Defend endpoints + * @param endpointAgentId + * @param enabled + * + * @private + */ +const useResponderDataForEndpointHost = ( + endpointAgentId: string, + enabled: boolean = true +): ResponderDataForEndpointHost => { + // FIXME:PT is this the correct API to call? or should we call the agent status api instead + + const { + data: endpointHostInfo, + isFetching, + error, + } = useGetEndpointDetails(endpointAgentId, { + enabled, + }); + + return useMemo(() => { + const response: ResponderDataForEndpointHost = { + isDisabled: false, + tooltip: undefined, + capabilities: [], + hostName: '', + platform: '', + }; + + if (!enabled) { + response.isDisabled = true; + return response; + } + + if (isFetching) { + response.isDisabled = true; + response.tooltip = LOADING_ENDPOINT_DATA_TOOLTIP; + return response; + } + + // if we got an error, and it's a 404, it means the endpoint is not from the endpoint host + if (error && error.body?.statusCode === 404) { + response.isDisabled = true; + response.tooltip = NOT_FROM_ENDPOINT_HOST_TOOLTIP; + return response; + } + + // if we got an error and, + // it's a 400 with unenrolled in the error message (alerts can exist for endpoint that are no longer around) + // or, + // the Host status is `unenrolled` + if ( + (error && error.body?.statusCode === 400 && error.body?.message.includes('unenrolled')) || + endpointHostInfo?.host_status === HostStatus.UNENROLLED + ) { + response.isDisabled = true; + response.tooltip = HOST_ENDPOINT_UNENROLLED_TOOLTIP; + return response; + } + + // return general error tooltip + if (error) { + response.isDisabled = true; + response.tooltip = METADATA_API_ERROR_TOOLTIP; + } + + response.capabilities = (endpointHostInfo?.metadata.Endpoint.capabilities ?? + []) as EndpointCapabilities[]; + response.hostName = endpointHostInfo?.metadata.host.name ?? ''; + response.platform = endpointHostInfo?.metadata.host.os.name.toLowerCase() ?? ''; + + return response; + }, [ + enabled, + isFetching, + error, + endpointHostInfo?.host_status, + endpointHostInfo?.metadata.Endpoint.capabilities, + endpointHostInfo?.metadata.host.name, + endpointHostInfo?.metadata.host.os.name, + ]); +}; + +export interface UseResponderActionDataProps { + agentId: string; + agentType: ResponseActionAgentType; + onClick?: () => void; +} + +/** + * Returns the data necessary to render a Responder action item (ex. menu item) when only the + * `agentId` and `agentType` is available (ex. when showing the `Respond` button on the Host + * details page of SIEM + * @param onClick + * @param agentId + * @param agentType + */ +export const useResponderActionData = ({ + onClick, + agentId, + agentType, +}: UseResponderActionDataProps): ResponderActionData => { + const isEndpointHost = agentType === 'endpoint'; + + const showResponseActionsConsole = useWithShowResponder(); + const { tooltip, isDisabled, capabilities, hostName, platform } = useResponderDataForEndpointHost( + agentId, + isEndpointHost + ); + + // TODO:PT add support for other agent types once we add the `Respond` button to the Host details page in SIEM + + const handleResponseActionsClick = useCallback(() => { + if (!isDisabled) { + showResponseActionsConsole({ + agentId, + agentType, + hostName, + platform, + capabilities: isEndpointHost ? capabilities : [], + }); + + if (onClick) { + onClick(); + } + } + }, [ + isDisabled, + showResponseActionsConsole, + agentId, + agentType, + hostName, + platform, + isEndpointHost, + capabilities, + onClick, + ]); + + return useMemo(() => { + return { + isDisabled: isEndpointHost ? isDisabled : true, + tooltip: isEndpointHost ? tooltip : NOT_FROM_ENDPOINT_HOST_TOOLTIP, + handleResponseActionsClick, + }; + }, [handleResponseActionsClick, isDisabled, isEndpointHost, tooltip]); +}; diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_item.test.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_item.test.tsx new file mode 100644 index 00000000000000..b499f8a795fa98 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_item.test.tsx @@ -0,0 +1,61 @@ +/* + * 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 { useResponderActionItem } from './use_responder_action_item'; +import { useUserPrivileges as _useUserPrivileges } from '../../../user_privileges'; +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import type { AppContextTestRender } from '../../../../mock/endpoint'; +import { createAppRootMockRenderer } from '../../../../mock/endpoint'; +import { endpointAlertDataMock } from '../../../../mock/endpoint/endpoint_alert_data_mock'; + +jest.mock('../../../user_privileges'); +jest.mock('./use_responder_action_data'); + +const useUserPrivilegesMock = _useUserPrivileges as jest.Mock; + +describe('useResponderActionItem', () => { + let alertDetailItemData: TimelineEventsDetailsItem[]; + let renderHook: () => ReturnType; + + beforeEach(() => { + const appContextMock = createAppRootMockRenderer(); + + // This is on purpose - an alert for an unsupported agent type. The menu item should always be + // visible as long as the user has authz to it. In this case it will be disabled. + alertDetailItemData = endpointAlertDataMock.generateAlertDetailsItemDataForAgentType('foo'); + + renderHook = () => + appContextMock.renderHook(() => useResponderActionItem(alertDetailItemData, () => {})); + + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canAccessResponseConsole: true }, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should return Respond action menu item if user has Authz', () => { + expect(renderHook().result.current).toHaveLength(1); + }); + + it('should NOT return the Respond action menu item if user is not Authorized', () => { + useUserPrivilegesMock.mockReturnValue({ + endpointPrivileges: { loading: false, canAccessResponseConsole: false }, + }); + expect(renderHook().result.current).toHaveLength(0); + }); + + it('should NOT return the Respond action menu item for Events', () => { + alertDetailItemData = endpointAlertDataMock.generateAlertDetailsItemDataForAgentType('foo', { + 'kibana.alert.rule.uuid': undefined, + }); + + expect(renderHook().result.current).toHaveLength(0); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_item.tsx similarity index 52% rename from x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx rename to x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_item.tsx index 57b51c23f2032c..6ccc6b4447907f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_item.tsx @@ -8,14 +8,10 @@ import React, { useMemo } from 'react'; import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; -import { isAlertFromCrowdstrikeEvent } from '../../../common/utils/crowdstrike_alert_check'; -import { isAlertFromSentinelOneEvent } from '../../../common/utils/sentinelone_alert_check'; -import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; -import { useUserPrivileges } from '../../../common/components/user_privileges'; -import { isTimelineEventItemAnAlert } from '../../../common/utils/endpoint_alert_check'; -import { getFieldValue } from '../host_isolation/helpers'; -import type { AlertTableContextMenuItem } from '../alerts_table/types'; -import { useResponderActionData } from './use_responder_action_data'; +import { useAlertResponseActionsSupport } from '../../../../hooks/endpoint/use_alert_response_actions_support'; +import { useUserPrivileges } from '../../../user_privileges'; +import type { AlertTableContextMenuItem } from '../../../../../detections/components/alerts_table/types'; +import { useWithResponderActionDataFromAlert } from './use_responder_action_data'; export const useResponderActionItem = ( eventDetailsData: TimelineEventsDetailsItem[] | null, @@ -23,36 +19,10 @@ export const useResponderActionItem = ( ): AlertTableContextMenuItem[] => { const { loading: isAuthzLoading, canAccessResponseConsole } = useUserPrivileges().endpointPrivileges; - - const isAlert = useMemo(() => { - return isTimelineEventItemAnAlert(eventDetailsData || []); - }, [eventDetailsData]); - - const endpointId: string = useMemo( - () => getFieldValue({ category: 'agent', field: 'agent.id' }, eventDetailsData), - [eventDetailsData] - ); - - const agentType: ResponseActionAgentType = useMemo(() => { - if (!eventDetailsData) { - return 'endpoint'; - } - - if (isAlertFromSentinelOneEvent({ data: eventDetailsData })) { - return 'sentinel_one'; - } - if (isAlertFromCrowdstrikeEvent({ data: eventDetailsData })) { - return 'crowdstrike'; - } - - return 'endpoint'; - }, [eventDetailsData]); - - const { handleResponseActionsClick, isDisabled, tooltip } = useResponderActionData({ - endpointId, + const { isAlert } = useAlertResponseActionsSupport(eventDetailsData); + const { handleResponseActionsClick, isDisabled, tooltip } = useWithResponderActionDataFromAlert({ onClick, - agentType, - eventData: agentType !== 'endpoint' ? eventDetailsData : null, + eventData: eventDetailsData, }); return useMemo(() => { diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/index.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/index.ts new file mode 100644 index 00000000000000..c030b4780dd267 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/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 './from_alerts'; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.test.ts b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.test.ts index 60bc2b7f3ce316..fc793df1025e7e 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.test.ts @@ -5,73 +5,41 @@ * 2.0. */ -import { isAlertFromEndpointEvent } from '../../utils/endpoint_alert_check'; -import { - isAlertFromSentinelOneEvent, - SENTINEL_ONE_AGENT_ID_FIELD, -} from '../../utils/sentinelone_alert_check'; -import { - CROWDSTRIKE_AGENT_ID_FIELD, - isAlertFromCrowdstrikeEvent, -} from '../../utils/crowdstrike_alert_check'; -import { renderHook } from '@testing-library/react-hooks'; +import type { UseSummaryRowsProps } from './get_alert_summary_rows'; import { useSummaryRows } from './get_alert_summary_rows'; -import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; - -jest.mock('../../utils/endpoint_alert_check'); -jest.mock('../../utils/sentinelone_alert_check'); -jest.mock('../../utils/crowdstrike_alert_check'); -jest.mock('../../hooks/use_experimental_features', () => ({ - useIsExperimentalFeatureEnabled: jest.fn(), -})); +import { createAppRootMockRenderer, endpointAlertDataMock } from '../../mock/endpoint'; +import type { RenderHookResult } from '@testing-library/react-hooks/src/types'; +import type { AlertSummaryRow } from './helpers'; describe('useSummaryRows', () => { - const mockData: TimelineEventsDetailsItem[] = [ - { - category: 'event', - field: 'event.category', - originalValue: ['process'], - values: ['process'], - isObjectArray: false, - }, - { - category: 'kibana', - field: 'kibana.alert.rule.uuid', - originalValue: 'rule-uuid', - values: ['rule-uuid'], - isObjectArray: false, - }, - { - category: 'host', - field: 'host.name', - originalValue: 'test-host', - values: ['text-host'], - isObjectArray: false, - }, - ]; - - const mockBrowserFields = {}; - const mockScopeId = 'scope-id'; - const mockEventId = 'event-id'; - const mockInvestigationFields: string[] = []; + let hookProps: UseSummaryRowsProps; + let renderHook: () => RenderHookResult; beforeEach(() => { - jest.clearAllMocks(); - (isAlertFromEndpointEvent as jest.Mock).mockReturnValue(true); - (isAlertFromCrowdstrikeEvent as jest.Mock).mockReturnValue(false); + const appContextMock = createAppRootMockRenderer(); + + appContextMock.setExperimentalFlag({ + responseActionsSentinelOneV1Enabled: true, + responseActionsCrowdstrikeManualHostIsolationEnabled: true, + }); + + hookProps = { + data: endpointAlertDataMock.generateEndpointAlertDetailsItemData(), + browserFields: {}, + scopeId: 'scope-id', + eventId: 'event-id', + investigationFields: [], + }; + + renderHook = () => { + return appContextMock.renderHook(() => + useSummaryRows(hookProps) + ); + }; }); it('returns summary rows for default event categories', () => { - const { result } = renderHook(() => - useSummaryRows({ - data: mockData, - browserFields: mockBrowserFields, - scopeId: mockScopeId, - eventId: mockEventId, - investigationFields: mockInvestigationFields, - }) - ); + const { result } = renderHook(); expect(result.current).toEqual( expect.arrayContaining([ @@ -81,17 +49,7 @@ describe('useSummaryRows', () => { }); it('excludes fields not related to the event source', () => { - (isAlertFromEndpointEvent as jest.Mock).mockReturnValue(false); - - const { result } = renderHook(() => - useSummaryRows({ - data: mockData, - browserFields: mockBrowserFields, - scopeId: mockScopeId, - eventId: mockEventId, - investigationFields: mockInvestigationFields, - }) - ); + const { result } = renderHook(); expect(result.current).not.toEqual( expect.arrayContaining([ @@ -104,70 +62,32 @@ describe('useSummaryRows', () => { }); it('includes sentinel_one agent status field', () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); - (isAlertFromSentinelOneEvent as jest.Mock).mockReturnValue(true); - - const sentinelOneData: TimelineEventsDetailsItem[] = [ - ...mockData, - { - category: 'host', - field: SENTINEL_ONE_AGENT_ID_FIELD, - originalValue: 'sentinelone-agent-id', - values: ['sentinelone-agent-id'], - isObjectArray: false, - }, - ]; - - const { result } = renderHook(() => - useSummaryRows({ - data: sentinelOneData, - browserFields: mockBrowserFields, - scopeId: mockScopeId, - eventId: mockEventId, - investigationFields: mockInvestigationFields, - }) - ); + hookProps.data = endpointAlertDataMock.generateSentinelOneAlertDetailsItemData(); + const { result } = renderHook(); expect(result.current).toEqual( expect.arrayContaining([ expect.objectContaining({ title: 'Agent status', - description: expect.objectContaining({ values: ['sentinelone-agent-id'] }), + description: expect.objectContaining({ + values: ['abfe4a35-d5b4-42a0-a539-bd054c791769'], + }), }), ]) ); }); it('includes crowdstrike agent status field', () => { - (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); - (isAlertFromCrowdstrikeEvent as jest.Mock).mockReturnValue(true); - - const crowdstrikeData: TimelineEventsDetailsItem[] = [ - ...mockData, - { - category: 'host', - field: CROWDSTRIKE_AGENT_ID_FIELD, - originalValue: 'crowdstrike-agent-id', - values: ['crowdstrike-agent-id'], - isObjectArray: false, - }, - ]; - - const { result } = renderHook(() => - useSummaryRows({ - data: crowdstrikeData, - browserFields: mockBrowserFields, - scopeId: mockScopeId, - eventId: mockEventId, - investigationFields: mockInvestigationFields, - }) - ); + hookProps.data = endpointAlertDataMock.generateCrowdStrikeAlertDetailsItemData(); + const { result } = renderHook(); expect(result.current).toEqual( expect.arrayContaining([ expect.objectContaining({ title: 'Agent status', - description: expect.objectContaining({ values: ['crowdstrike-agent-id'] }), + description: expect.objectContaining({ + values: ['abfe4a35-d5b4-42a0-a539-bd054c791769'], + }), }), ]) ); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx index b079d3575f7c79..f632e48301b675 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx @@ -9,6 +9,9 @@ import { find, isEmpty, uniqBy } from 'lodash/fp'; import { ALERT_RULE_PARAMETERS, ALERT_RULE_TYPE } from '@kbn/rule-data-utils'; import { EventCode, EventCategory } from '@kbn/securitysolution-ecs'; +import { RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD } from '../../../../common/endpoint/service/response_actions/constants'; +import { isResponseActionsAlertAgentIdField } from '../../lib/endpoint'; +import { useAlertResponseActionsSupport } from '../../hooks/endpoint/use_alert_response_actions_support'; import * as i18n from './translations'; import type { BrowserFields } from '../../../../common/search_strategy/index_fields'; import { @@ -33,17 +36,6 @@ import { getEnrichedFieldInfo } from './helpers'; import type { EventSummaryField, EnrichedFieldInfo } from './types'; import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy/timeline'; -import { isAlertFromEndpointEvent } from '../../utils/endpoint_alert_check'; -import { - SENTINEL_ONE_AGENT_ID_FIELD, - isAlertFromSentinelOneEvent, -} from '../../utils/sentinelone_alert_check'; -import { - CROWDSTRIKE_AGENT_ID_FIELD, - isAlertFromCrowdstrikeEvent, -} from '../../utils/crowdstrike_alert_check'; -import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; - const THRESHOLD_TERMS_FIELD = `${ALERT_THRESHOLD_RESULT}.terms.field`; const THRESHOLD_TERMS_VALUE = `${ALERT_THRESHOLD_RESULT}.terms.value`; const THRESHOLD_CARDINALITY_FIELD = `${ALERT_THRESHOLD_RESULT}.cardinality.field`; @@ -56,12 +48,12 @@ const alwaysDisplayedFields: EventSummaryField[] = [ // ENDPOINT-related field // { id: 'agent.id', overrideField: AGENT_STATUS_FIELD_NAME, label: i18n.AGENT_STATUS }, { - id: SENTINEL_ONE_AGENT_ID_FIELD, + id: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one, overrideField: AGENT_STATUS_FIELD_NAME, label: i18n.AGENT_STATUS, }, { - id: CROWDSTRIKE_AGENT_ID_FIELD, + id: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.crowdstrike, overrideField: AGENT_STATUS_FIELD_NAME, label: i18n.AGENT_STATUS, }, @@ -307,6 +299,16 @@ export function getEventCategoriesFromData(data: TimelineEventsDetailsItem[]): E return { primaryEventCategory, allEventCategories }; } +export interface UseSummaryRowsProps { + data: TimelineEventsDetailsItem[]; + browserFields: BrowserFields; + scopeId: string; + eventId: string; + investigationFields?: string[]; + isDraggable?: boolean; + isReadOnly?: boolean; +} + export const useSummaryRows = ({ data, browserFields, @@ -315,21 +317,9 @@ export const useSummaryRows = ({ isDraggable = false, isReadOnly = false, investigationFields, -}: { - data: TimelineEventsDetailsItem[]; - browserFields: BrowserFields; - scopeId: string; - eventId: string; - investigationFields?: string[]; - isDraggable?: boolean; - isReadOnly?: boolean; -}) => { - const sentinelOneManualHostActionsEnabled = useIsExperimentalFeatureEnabled( - 'sentinelOneManualHostActionsEnabled' - ); - const crowdstrikeManualHostActionsEnabled = useIsExperimentalFeatureEnabled( - 'responseActionsCrowdstrikeManualHostIsolationEnabled' - ); +}: UseSummaryRowsProps): AlertSummaryRow[] => { + const responseActionsSupport = useAlertResponseActionsSupport(data); + return useMemo(() => { const eventCategories = getEventCategoriesFromData(data); @@ -381,22 +371,14 @@ export const useSummaryRows = ({ isReadOnly, }; - if (field.id === 'agent.id' && !isAlertFromEndpointEvent({ data })) { - return acc; - } - + // If the field is one used by a supported Response Actions agentType, + // and the alert's host supports response actions + // but the alert field is not the one that the agentType on the alert host uses, + // then exit and return accumulator if ( - field.id === SENTINEL_ONE_AGENT_ID_FIELD && - sentinelOneManualHostActionsEnabled && - !isAlertFromSentinelOneEvent({ data }) - ) { - return acc; - } - - if ( - field.id === CROWDSTRIKE_AGENT_ID_FIELD && - crowdstrikeManualHostActionsEnabled && - !isAlertFromCrowdstrikeEvent({ data }) + isResponseActionsAlertAgentIdField(field.id) && + responseActionsSupport.isSupported && + responseActionsSupport.details.agentIdField !== field.id ) { return acc; } @@ -429,15 +411,15 @@ export const useSummaryRows = ({ }, []) : []; }, [ - browserFields, data, + investigationFields, + scopeId, + browserFields, eventId, isDraggable, - scopeId, isReadOnly, - investigationFields, - sentinelOneManualHostActionsEnabled, - crowdstrikeManualHostActionsEnabled, + responseActionsSupport.details.agentIdField, + responseActionsSupport.isSupported, ]); }; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx index dccea29321671b..693df1902873a3 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx @@ -23,8 +23,7 @@ import { AGENT_STATUS_FIELD_NAME, QUARANTINED_PATH_FIELD_NAME, } from '../../../timelines/components/timeline/body/renderers/constants'; -import { SENTINEL_ONE_AGENT_ID_FIELD } from '../../utils/sentinelone_alert_check'; -import { CROWDSTRIKE_AGENT_ID_FIELD } from '../../utils/crowdstrike_alert_check'; +import { RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD } from '../../../../common/endpoint/service/response_actions/constants'; /** * Defines the behavior of the search input that appears above the table of data @@ -183,8 +182,8 @@ export function getEnrichedFieldInfo({ export const FIELDS_WITHOUT_ACTIONS: { [field: string]: boolean } = { [AGENT_STATUS_FIELD_NAME]: true, [QUARANTINED_PATH_FIELD_NAME]: true, - [SENTINEL_ONE_AGENT_ID_FIELD]: true, - [CROWDSTRIKE_AGENT_ID_FIELD]: true, + [RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one]: true, + [RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.crowdstrike]: true, }; /** diff --git a/x-pack/plugins/security_solution/public/common/hooks/endpoint/__mocks__/use_alert_response_actions_support.ts b/x-pack/plugins/security_solution/public/common/hooks/endpoint/__mocks__/use_alert_response_actions_support.ts new file mode 100644 index 00000000000000..dcced934f3bc93 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/hooks/endpoint/__mocks__/use_alert_response_actions_support.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AlertResponseActionsSupport } from '../use_alert_response_actions_support'; +import { + RESPONSE_ACTION_API_COMMANDS_NAMES, + RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD, +} from '../../../../../common/endpoint/service/response_actions/constants'; + +const useAlertResponseActionsSupportMock = (): AlertResponseActionsSupport => { + return { + isSupported: true, + unsupportedReason: undefined, + isAlert: true, + details: { + agentId: '123', + agentType: 'endpoint', + agentIdField: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.endpoint, + hostName: 'host-a', + platform: 'linux', + agentSupport: RESPONSE_ACTION_API_COMMANDS_NAMES.reduce< + AlertResponseActionsSupport['details']['agentSupport'] + >((acc, responseActionName) => { + acc[responseActionName] = true; + return acc; + }, {} as AlertResponseActionsSupport['details']['agentSupport']), + }, + }; +}; + +export { useAlertResponseActionsSupportMock as useAlertResponseActionsSupport }; diff --git a/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_alert_response_actions_support.test.ts b/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_alert_response_actions_support.test.ts new file mode 100644 index 00000000000000..b5a07b34c65bb6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_alert_response_actions_support.test.ts @@ -0,0 +1,207 @@ +/* + * 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 { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import type { AppContextTestRender } from '../../mock/endpoint'; +import { createAppRootMockRenderer, endpointAlertDataMock } from '../../mock/endpoint'; +import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; +import { + RESPONSE_ACTION_AGENT_TYPE, + RESPONSE_ACTION_API_COMMANDS_NAMES, + RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD, +} from '../../../../common/endpoint/service/response_actions/constants'; +import type { AlertResponseActionsSupport } from './use_alert_response_actions_support'; +import { + ALERT_EVENT_DATA_MISSING_AGENT_ID_FIELD, + RESPONSE_ACTIONS_ONLY_SUPPORTED_ON_ALERTS, + useAlertResponseActionsSupport, +} from './use_alert_response_actions_support'; +import { isAgentTypeAndActionSupported } from '../../lib/endpoint'; +import type { DeepPartial } from 'utility-types'; +import { merge } from 'lodash'; + +describe('When using `useAlertResponseActionsSupport()` hook', () => { + let appContextMock: AppContextTestRender; + let alertDetailItemData: TimelineEventsDetailsItem[]; + let renderHook: () => ReturnType; + + const getExpectedResult = ( + overrides: DeepPartial = {}, + options: Partial<{ + /* If true, then all properties in `agentSupport` will be false */ + noAgentSupport: boolean; + }> = {} + ): AlertResponseActionsSupport => { + const agentType = overrides.details?.agentType ?? 'endpoint'; + + return merge( + { + isAlert: true, + isSupported: true, + unsupportedReason: undefined, + details: { + agentId: 'abfe4a35-d5b4-42a0-a539-bd054c791769', + agentIdField: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD[agentType], + agentSupport: RESPONSE_ACTION_API_COMMANDS_NAMES.reduce((acc, commandName) => { + acc[commandName] = options.noAgentSupport + ? false + : isAgentTypeAndActionSupported(agentType, commandName); + return acc; + }, {} as AlertResponseActionsSupport['details']['agentSupport']), + agentType, + hostName: 'elastic-host-win', + platform: 'windows', + }, + }, + overrides + ); + }; + + beforeEach(() => { + appContextMock = createAppRootMockRenderer(); + + // Enable feature flags by default + appContextMock.setExperimentalFlag({ + responseActionsSentinelOneV1Enabled: true, + responseActionsSentinelOneGetFileEnabled: true, + responseActionsCrowdstrikeManualHostIsolationEnabled: true, + }); + + alertDetailItemData = endpointAlertDataMock.generateEndpointAlertDetailsItemData(); + renderHook = () => + appContextMock.renderHook(() => useAlertResponseActionsSupport(alertDetailItemData)); + }); + + it.each(RESPONSE_ACTION_AGENT_TYPE)( + 'should return expected response for agentType: `%s`', + (agentType) => { + alertDetailItemData = + endpointAlertDataMock.generateAlertDetailsItemDataForAgentType(agentType); + const { result } = renderHook(); + + expect(result.current).toEqual(getExpectedResult({ details: { agentType } })); + } + ); + + it('should set `isSupported` to `false` if no alert details item data is provided', () => { + alertDetailItemData = []; + + expect(renderHook().result.current).toEqual( + getExpectedResult( + { + isAlert: false, + isSupported: false, + unsupportedReason: RESPONSE_ACTIONS_ONLY_SUPPORTED_ON_ALERTS, + details: { + agentId: '', + agentIdField: '', + hostName: '', + platform: '', + }, + }, + { noAgentSupport: true } + ) + ); + }); + + it('should set `isSupported` to `false` for if not an Alert', () => { + alertDetailItemData = endpointAlertDataMock.generateAlertDetailsItemDataForAgentType( + 'sentinel_one', + { 'kibana.alert.rule.uuid': undefined } + ); + + expect(renderHook().result.current).toEqual( + getExpectedResult({ + isAlert: false, + isSupported: false, + unsupportedReason: RESPONSE_ACTIONS_ONLY_SUPPORTED_ON_ALERTS, + details: { + agentType: 'sentinel_one', + agentIdField: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one, + }, + }) + ); + }); + + it('should set `isSupported` to `false` if unable to get agent id', () => { + alertDetailItemData = endpointAlertDataMock.generateEndpointAlertDetailsItemData({ + [RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.endpoint]: undefined, + }); + + expect(renderHook().result.current).toEqual( + getExpectedResult({ + isSupported: false, + unsupportedReason: ALERT_EVENT_DATA_MISSING_AGENT_ID_FIELD('Elastic Defend', 'agent.id'), + details: { agentId: '' }, + }) + ); + }); + + it('should set `isSupported` to `false` if unable to determine agent type', () => { + alertDetailItemData = endpointAlertDataMock.generateCrowdStrikeAlertDetailsItemData({ + 'event.module': undefined, + }); + + expect(renderHook().result.current).toEqual( + getExpectedResult( + { + isSupported: false, + details: { + agentId: '', + agentIdField: '', + }, + }, + { noAgentSupport: true } + ) + ); + }); + + it('should default `details.agentType` to `endpoint` for non-supported hosts', () => { + alertDetailItemData = endpointAlertDataMock.generateAlertDetailsItemDataForAgentType('foo'); + + expect(renderHook().result.current).toEqual( + getExpectedResult( + { + isSupported: false, + details: { + agentId: '', + agentIdField: '', + }, + }, + { noAgentSupport: true } + ) + ); + }); + + it.each( + RESPONSE_ACTION_AGENT_TYPE.filter((agentType) => agentType !== 'endpoint') as Array< + Exclude + > + )('should set `isSupported` to `false` for [%s] if feature flag is disabled', (agentType) => { + switch (agentType) { + case 'sentinel_one': + appContextMock.setExperimentalFlag({ responseActionsSentinelOneV1Enabled: false }); + break; + case 'crowdstrike': + appContextMock.setExperimentalFlag({ + responseActionsCrowdstrikeManualHostIsolationEnabled: false, + }); + break; + default: + throw new Error(`Unknown agent type: ${agentType}`); + } + + alertDetailItemData = endpointAlertDataMock.generateAlertDetailsItemDataForAgentType(agentType); + + expect(renderHook().result.current).toEqual( + getExpectedResult({ + isSupported: false, + details: { agentType }, + }) + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_alert_response_actions_support.ts b/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_alert_response_actions_support.ts new file mode 100644 index 00000000000000..7d4698695c3b85 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_alert_response_actions_support.ts @@ -0,0 +1,241 @@ +/* + * 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 { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { useMemo } from 'react'; +import { find, some } from 'lodash/fp'; +import { i18n } from '@kbn/i18n'; +import { getAlertDetailsFieldValue } from '../../lib/endpoint/utils/get_event_details_field_values'; +import { isAgentTypeAndActionSupported } from '../../lib/endpoint'; +import type { + ResponseActionAgentType, + ResponseActionsApiCommandNames, +} from '../../../../common/endpoint/service/response_actions/constants'; +import { + RESPONSE_ACTION_API_COMMANDS_NAMES, + RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD, +} from '../../../../common/endpoint/service/response_actions/constants'; +import { getAgentTypeName } from '../../translations'; + +export const ALERT_EVENT_DATA_MISSING_AGENT_ID_FIELD = ( + agentTypeName: string, + missingField: string +): string => { + return i18n.translate( + 'xpack.securitySolution.useAlertResponseActionsSupport.missingAgentIdField', + { + defaultMessage: + 'Alert event data missing {agentTypeName} agent identifier field ({missingField})', + values: { + missingField, + agentTypeName, + }, + } + ); +}; + +export const RESPONSE_ACTIONS_ONLY_SUPPORTED_ON_ALERTS = i18n.translate( + 'xpack.securitySolution.useAlertResponseActionsSupport.notAnAlert', + { defaultMessage: 'Response actions are only supported for Alerts (not events)' } +); + +export interface AlertResponseActionsSupport { + /** Does the host/agent for the given alert have support for response actions */ + isSupported: boolean; + + /** A i18n'd string value indicating the reason why the host does is unsupported */ + unsupportedReason: string | undefined; + + /** + * If the Event Data provide was for a SIEM alert (generated as a result of a Rule run) or + * just an event. + */ + isAlert: boolean; + + /** + * Full details around support for response actions. + * NOTE That some data may not be blank if `isSupported` is `false` + */ + details: { + /** Defaults to `endpoint` when unable to determine agent type */ + agentType: ResponseActionAgentType; + /** Agent ID could be an empty string if `isSupported` is `false` */ + agentId: string; + /** Host name could be an empty string if `isSupported` is `false` */ + hostName: string; + /** The OS platform - normally the ECS value from `host.os.family. could be an empty string if `isSupported` is `false` */ + platform: string; + /** + * A map with the response actions supported by this alert's agent type. This is only what is + * supported, not what the user has privileges to execute. + */ + agentSupport: AlertAgentActionsSupported; + /** The field that was/is used to store the agent ID in the ES document */ + agentIdField: string; + }; +} + +type AlertAgentActionsSupported = Record; + +/** + * Determines the level of support that an alert's host has for Response Actions. + * This hook already checks feature flags to determine the level of support that we have available + */ +export const useAlertResponseActionsSupport = ( + eventData: TimelineEventsDetailsItem[] | null = [] +): AlertResponseActionsSupport => { + const isAlert = useMemo(() => { + return some({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, eventData); + }, [eventData]); + + const agentType: ResponseActionAgentType | undefined = useMemo(() => { + if ((find({ field: 'agent.type' }, eventData)?.values ?? []).includes('endpoint')) { + return 'endpoint'; + } + + const eventModuleValues = find({ field: 'event.module' }, eventData)?.values ?? []; + + if (eventModuleValues.includes('sentinel_one')) { + return 'sentinel_one'; + } + + if (eventModuleValues.includes('crowdstrike')) { + return 'crowdstrike'; + } + + return undefined; + }, [eventData]); + + const isFeatureEnabled: boolean = useMemo(() => { + return agentType ? isAgentTypeAndActionSupported(agentType) : false; + }, [agentType]); + + const agentId: string = useMemo(() => { + if (!agentType) { + return ''; + } + + if (agentType === 'endpoint') { + return getAlertDetailsFieldValue({ category: 'agent', field: 'agent.id' }, eventData); + } + + if (agentType === 'sentinel_one') { + return getAlertDetailsFieldValue( + { category: 'observer', field: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one }, + eventData + ); + } + + if (agentType === 'crowdstrike') { + return getAlertDetailsFieldValue( + { category: 'crowdstrike', field: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.crowdstrike }, + eventData + ); + } + + return ''; + }, [agentType, eventData]); + + const doesHostSupportResponseActions = useMemo(() => { + return Boolean(isFeatureEnabled && isAlert && agentId && agentType); + }, [agentId, agentType, isAlert, isFeatureEnabled]); + + const agentIdField = useMemo(() => { + if (agentType) { + return RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD[agentType]; + } + + return ''; + }, [agentType]); + + const supportedActions = useMemo(() => { + return RESPONSE_ACTION_API_COMMANDS_NAMES.reduce( + (acc, responseActionName) => { + acc[responseActionName] = false; + + if (agentType && isFeatureEnabled) { + acc[responseActionName] = isAgentTypeAndActionSupported( + agentType, + responseActionName, + 'manual' + ); + } + + return acc; + }, + {} as AlertAgentActionsSupported + ); + }, [agentType, isFeatureEnabled]); + + const hostName = useMemo(() => { + // TODO:PT need to check if crowdstrike event has `host.name` + if (agentType === 'crowdstrike') { + return getAlertDetailsFieldValue( + { category: 'crowdstrike', field: 'crowdstrike.event.HostName' }, + eventData + ); + } + + return getAlertDetailsFieldValue({ category: 'host', field: 'host.name' }, eventData); + }, [agentType, eventData]); + + const platform = useMemo(() => { + // TODO:PT need to check if crowdstrike event has `host.os.family` + if (agentType === 'crowdstrike') { + return getAlertDetailsFieldValue( + { category: 'crowdstrike', field: 'crowdstrike.event.Platform' }, + eventData + ); + } + + return getAlertDetailsFieldValue({ category: 'host', field: 'host.os.family' }, eventData); + }, [agentType, eventData]); + + const unsupportedReason = useMemo(() => { + if (!doesHostSupportResponseActions) { + if (!isAlert) { + return RESPONSE_ACTIONS_ONLY_SUPPORTED_ON_ALERTS; + } + + if (!agentType) { + // No message is provided for this condition because the + // return from this hook will always default to `endpoint` + return; + } + + if (!agentId) { + return ALERT_EVENT_DATA_MISSING_AGENT_ID_FIELD(getAgentTypeName(agentType), agentIdField); + } + } + }, [agentId, agentIdField, agentType, doesHostSupportResponseActions, isAlert]); + + return useMemo(() => { + return { + isSupported: doesHostSupportResponseActions, + unsupportedReason, + isAlert, + details: { + agentType: agentType || 'endpoint', + agentId, + hostName, + platform, + agentIdField, + agentSupport: supportedActions, + }, + }; + }, [ + agentId, + agentIdField, + agentType, + doesHostSupportResponseActions, + hostName, + isAlert, + platform, + supportedActions, + unsupportedReason, + ]); +}; diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint_isolation/index.test.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_isolation/index.test.ts similarity index 91% rename from x-pack/plugins/security_solution/public/common/lib/endpoint_isolation/index.test.ts rename to x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_isolation/index.test.ts index ebfac9c6508b6b..13c9af46fbac51 100644 --- a/x-pack/plugins/security_solution/public/common/lib/endpoint_isolation/index.test.ts +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_isolation/index.test.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { KibanaServices } from '../kibana'; +import { KibanaServices } from '../../kibana'; import { coreMock } from '@kbn/core/public/mocks'; import { isolateHost, unIsolateHost } from '.'; import { hostIsolationRequestBodyMock } from './mocks'; import { ISOLATE_HOST_ROUTE_V2, UNISOLATE_HOST_ROUTE_V2, -} from '../../../../common/endpoint/constants'; +} from '../../../../../common/endpoint/constants'; -jest.mock('../kibana'); +jest.mock('../../kibana'); describe('When using Host Isolation library', () => { const mockKibanaServices = KibanaServices.get as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint_isolation/index.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_isolation/index.ts similarity index 84% rename from x-pack/plugins/security_solution/public/common/lib/endpoint_isolation/index.ts rename to x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_isolation/index.ts index 71cde358a17a37..dc119de848dec9 100644 --- a/x-pack/plugins/security_solution/public/common/lib/endpoint_isolation/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_isolation/index.ts @@ -8,12 +8,14 @@ import type { HostIsolationRequestBody, ResponseActionApiResponse, -} from '../../../../common/endpoint/types'; -import { KibanaServices } from '../kibana'; +} from '../../../../../common/endpoint/types'; +import { KibanaServices } from '../../kibana'; import { ISOLATE_HOST_ROUTE_V2, UNISOLATE_HOST_ROUTE_V2, -} from '../../../../common/endpoint/constants'; +} from '../../../../../common/endpoint/constants'; + +// FIXME:PT refactor usage of these and use common hooks /** Isolates a Host running either elastic endpoint or fleet agent */ export const isolateHost = async ( diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint_isolation/mocks.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_isolation/mocks.ts similarity index 81% rename from x-pack/plugins/security_solution/public/common/lib/endpoint_isolation/mocks.ts rename to x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_isolation/mocks.ts index 5540f4c9667733..4881fc3f1569fd 100644 --- a/x-pack/plugins/security_solution/public/common/lib/endpoint_isolation/mocks.ts +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_isolation/mocks.ts @@ -8,13 +8,13 @@ import type { HostIsolationRequestBody, HostIsolationResponse, -} from '../../../../common/endpoint/types'; -import type { ResponseProvidersInterface } from '../../mock/endpoint/http_handler_mock_factory'; -import { httpHandlerMockFactory } from '../../mock/endpoint/http_handler_mock_factory'; +} from '../../../../../common/endpoint/types'; +import type { ResponseProvidersInterface } from '../../../mock/endpoint/http_handler_mock_factory'; +import { httpHandlerMockFactory } from '../../../mock/endpoint/http_handler_mock_factory'; import { ISOLATE_HOST_ROUTE_V2, UNISOLATE_HOST_ROUTE_V2, -} from '../../../../common/endpoint/constants'; +} from '../../../../../common/endpoint/constants'; export const hostIsolationRequestBodyMock = (): HostIsolationRequestBody => { return { diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/endpoint_pending_actions.test.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/endpoint_pending_actions.test.ts similarity index 88% rename from x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/endpoint_pending_actions.test.ts rename to x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/endpoint_pending_actions.test.ts index 4431486885a03d..2b3a71104ff29b 100644 --- a/x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/endpoint_pending_actions.test.ts +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/endpoint_pending_actions.test.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { KibanaServices } from '../kibana'; +import { KibanaServices } from '../../kibana'; import { coreMock } from '@kbn/core/public/mocks'; import { fetchPendingActionsByAgentId } from './endpoint_pending_actions'; import { pendingActionsHttpMock, pendingActionsResponseMock } from './mocks'; -import { ACTION_STATUS_ROUTE } from '../../../../common/endpoint/constants'; +import { ACTION_STATUS_ROUTE } from '../../../../../common/endpoint/constants'; -jest.mock('../kibana'); +jest.mock('../../kibana'); describe('when using endpoint pending actions api service', () => { let coreHttp: ReturnType['http']; diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/endpoint_pending_actions.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/endpoint_pending_actions.ts similarity index 77% rename from x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/endpoint_pending_actions.ts rename to x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/endpoint_pending_actions.ts index 3d2d8cd5a4e96b..86e3a88cc0d2bf 100644 --- a/x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/endpoint_pending_actions.ts +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/endpoint_pending_actions.ts @@ -8,9 +8,11 @@ import type { PendingActionsRequestQuery, PendingActionsResponse, -} from '../../../../common/endpoint/types'; -import { KibanaServices } from '../kibana'; -import { ACTION_STATUS_ROUTE } from '../../../../common/endpoint/constants'; +} from '../../../../../common/endpoint/types'; +import { KibanaServices } from '../../kibana'; +import { ACTION_STATUS_ROUTE } from '../../../../../common/endpoint/constants'; + +// FIXME:PT refactor these to use common hooks /** * Retrieve a list of pending actions against the given Fleet Agent Ids provided on input diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/index.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/index.ts similarity index 100% rename from x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/index.ts rename to x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/index.ts diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/mocks.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/mocks.ts similarity index 82% rename from x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/mocks.ts rename to x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/mocks.ts index 1ce00bb86ab856..97d91eecc0b381 100644 --- a/x-pack/plugins/security_solution/public/common/lib/endpoint_pending_actions/mocks.ts +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/endpoint_pending_actions/mocks.ts @@ -8,10 +8,10 @@ import type { PendingActionsRequestQuery, PendingActionsResponse, -} from '../../../../common/endpoint/types'; -import type { ResponseProvidersInterface } from '../../mock/endpoint/http_handler_mock_factory'; -import { httpHandlerMockFactory } from '../../mock/endpoint/http_handler_mock_factory'; -import { ACTION_STATUS_ROUTE } from '../../../../common/endpoint/constants'; +} from '../../../../../common/endpoint/types'; +import type { ResponseProvidersInterface } from '../../../mock/endpoint/http_handler_mock_factory'; +import { httpHandlerMockFactory } from '../../../mock/endpoint/http_handler_mock_factory'; +import { ACTION_STATUS_ROUTE } from '../../../../../common/endpoint/constants'; export const pendingActionsResponseMock = (): PendingActionsResponse => ({ data: [ diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint/index.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/index.ts new file mode 100644 index 00000000000000..5bea833df9cad2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/index.ts @@ -0,0 +1,10 @@ +/* + * 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 './utils'; +export * from './endpoint_isolation'; +export * from './endpoint_pending_actions'; diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/helpers.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/get_event_details_field_values.ts similarity index 64% rename from x-pack/plugins/security_solution/public/detections/components/host_isolation/helpers.ts rename to x-pack/plugins/security_solution/public/common/lib/endpoint/utils/get_event_details_field_values.ts index 32fa616831dfb0..d07b557a8e6811 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/helpers.ts +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/get_event_details_field_values.ts @@ -4,11 +4,18 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { find } from 'lodash/fp'; -import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { find } from 'lodash/fp'; -export const getFieldValues = ( +/** + * Gets the array of values for a given field in an Alert Details data + * + * @param category + * @param field + * @param data + */ +const getEventDetailsFieldValues = ( { category, field, @@ -17,7 +24,7 @@ export const getFieldValues = ( field: string; }, data: TimelineEventsDetailsItem[] | null -) => { +): string[] => { const categoryCompat = category === 'signal' ? 'kibana' : category === 'kibana' ? 'signal' : category; const fieldCompat = @@ -28,11 +35,20 @@ export const getFieldValues = ( : field; return ( find({ category, field }, data)?.values ?? - find({ category: categoryCompat, field: fieldCompat }, data)?.values + find({ category: categoryCompat, field: fieldCompat }, data)?.values ?? + [] ); }; -export const getFieldValue = ( +/** + * Gets a single value for a given Alert Details data field. If the field has multiple values, + * the first one will be returned. + * + * @param category + * @param field + * @param data + */ +export const getAlertDetailsFieldValue = ( { category, field, @@ -41,7 +57,7 @@ export const getFieldValue = ( field: string; }, data: TimelineEventsDetailsItem[] | null -) => { - const currentField = getFieldValues({ category, field }, data); +): string => { + const currentField = getEventDetailsFieldValues({ category, field }, data); return currentField && currentField.length > 0 ? currentField[0] : ''; }; diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/index.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/index.ts new file mode 100644 index 00000000000000..b5e173e2c360fc --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './is_agent_type_and_action_supported'; +export * from './is_response_actions_alert_agent_id_field'; diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_agent_type_and_action_supported.test.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_agent_type_and_action_supported.test.ts new file mode 100644 index 00000000000000..79294c165ab22f --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_agent_type_and_action_supported.test.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + ResponseActionAgentType, + ResponseActionsApiCommandNames, + ResponseActionType, +} from '../../../../../common/endpoint/service/response_actions/constants'; +import { isAgentTypeAndActionSupported } from './is_agent_type_and_action_supported'; +import { ExperimentalFeaturesService } from '../../../experimental_features_service'; +import type { ExperimentalFeatures } from '../../../../../common'; +import { allowedExperimentalValues } from '../../../../../common'; + +jest.mock('../../../experimental_features_service'); + +describe('isAgentTypeAndActionSupported() util', () => { + const enableFeatures = (overrides: Partial = {}): void => { + (ExperimentalFeaturesService.get as jest.Mock).mockReturnValue({ + ...allowedExperimentalValues, + responseActionsSentinelOneGetFileEnabled: true, + responseActionsCrowdstrikeManualHostIsolationEnabled: true, + ...overrides, + }); + }; + + const disableS1GetFileFeature = () => { + enableFeatures({ responseActionsSentinelOneGetFileEnabled: false }); + }; + + const resetFeatures = (): void => { + (ExperimentalFeaturesService.get as jest.Mock).mockReturnValue({ + ...allowedExperimentalValues, + }); + }; + + beforeEach(() => { + enableFeatures(); + }); + + afterEach(() => { + resetFeatures(); + }); + + it.each` + agentType | actionName | actionType | expectedValue | runSetup + ${'endpoint'} | ${undefined} | ${undefined} | ${true} | ${undefined} + ${'endpoint'} | ${'isolate'} | ${'manual'} | ${true} | ${undefined} + ${'endpoint'} | ${'isolate'} | ${'automated'} | ${true} | ${undefined} + ${'sentinel_one'} | ${undefined} | ${undefined} | ${true} | ${undefined} + ${'sentinel_one'} | ${'isolate'} | ${'manual'} | ${true} | ${undefined} + ${'sentinel_one'} | ${'get-file'} | ${'manual'} | ${true} | ${undefined} + ${'sentinel_one'} | ${'get-file'} | ${undefined} | ${false} | ${disableS1GetFileFeature} + ${'crowdstrike'} | ${undefined} | ${undefined} | ${true} | ${undefined} + ${'crowdstrike'} | ${'isolate'} | ${'manual'} | ${true} | ${undefined} + ${'crowdstrike'} | ${'isolate'} | ${undefined} | ${false} | ${resetFeatures} + `( + 'should return `$expectedValue` for $agentType $actionName ($actionType)', + ({ + agentType, + actionName, + actionType, + expectedValue, + runSetup, + }: { + agentType: ResponseActionAgentType; + actionName?: ResponseActionsApiCommandNames; + actionType?: ResponseActionType; + runSetup?: () => void; + expectedValue: boolean; + }) => { + if (runSetup) { + runSetup(); + } + + expect(isAgentTypeAndActionSupported(agentType, actionName, actionType)).toBe(expectedValue); + } + ); +}); diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_agent_type_and_action_supported.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_agent_type_and_action_supported.ts new file mode 100644 index 00000000000000..ba70f96f1cfdef --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_agent_type_and_action_supported.ts @@ -0,0 +1,60 @@ +/* + * 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 { + ResponseActionAgentType, + ResponseActionsApiCommandNames, + ResponseActionType, +} from '../../../../../common/endpoint/service/response_actions/constants'; +import { isActionSupportedByAgentType } from '../../../../../common/endpoint/service/response_actions/is_response_action_supported'; +import { ExperimentalFeaturesService } from '../../../experimental_features_service'; + +/** + * Checks if a given Agent type is supported (aka: is feature flag enabled) and optionally + * also checks if a given response action is implemented for that agent type. + */ +export const isAgentTypeAndActionSupported = ( + agentType: ResponseActionAgentType, + actionName?: ResponseActionsApiCommandNames, + actionType: ResponseActionType = 'manual' +): boolean => { + const features = ExperimentalFeaturesService.get(); + const isSentinelOneV1Enabled = features.responseActionsSentinelOneV1Enabled; + const isSentinelOneGetFileEnabled = features.responseActionsSentinelOneGetFileEnabled; + const isCrowdstrikeHostIsolationEnabled = + features.responseActionsCrowdstrikeManualHostIsolationEnabled; + + const isAgentTypeSupported = + agentType === 'endpoint' || + (agentType === 'sentinel_one' && isSentinelOneV1Enabled) || + (agentType === 'crowdstrike' && isCrowdstrikeHostIsolationEnabled); + + let isActionNameSupported: boolean = + !actionName || isActionSupportedByAgentType(agentType, actionName, actionType); + + // if response action is supported, then do specific response action FF checks + if (isAgentTypeSupported && isActionNameSupported && actionName) { + switch (agentType) { + case 'sentinel_one': + switch (actionName) { + case 'get-file': + if (!isSentinelOneGetFileEnabled) { + isActionNameSupported = false; + } + break; + } + + break; + + case 'crowdstrike': + // Placeholder for future individual response actions FF checks + break; + } + } + + return Boolean(isAgentTypeSupported && isActionNameSupported); +}; diff --git a/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_response_actions_alert_agent_id_field.ts b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_response_actions_alert_agent_id_field.ts new file mode 100644 index 00000000000000..88b940ba3b7481 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/lib/endpoint/utils/is_response_actions_alert_agent_id_field.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 { RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD } from '../../../../../common/endpoint/service/response_actions/constants'; + +const SUPPORTED_ALERT_FIELDS: Readonly = Object.values( + RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD +); + +/** + * Checks to see if a given alert field (ex. `agent.id`) is used by Agents that have support for response actions. + */ +export const isResponseActionsAlertAgentIdField = (field: string): boolean => { + return SUPPORTED_ALERT_FIELDS.includes(field); +}; diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/endpoint_alert_data_mock.ts b/x-pack/plugins/security_solution/public/common/mock/endpoint/endpoint_alert_data_mock.ts new file mode 100644 index 00000000000000..96003266c1315f --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/endpoint_alert_data_mock.ts @@ -0,0 +1,248 @@ +/* + * 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 { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; +import { RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD } from '../../../../common/endpoint/service/response_actions/constants'; + +/** + * Provide overrides for data `fields`. If a field is set to `undefined`, then it will be removed + * from the array. If an override field name is not currently in the array, it will be added. + */ +interface AlertDetailsItemDataOverrides { + [field: string]: Partial | undefined; +} + +/** + * Will update (mutate) the data passed in with the override data defined + * @param data + * @param overrides + */ +const setAlertDetailsItemDataOverrides = ( + data: TimelineEventsDetailsItem[], + overrides: AlertDetailsItemDataOverrides +): TimelineEventsDetailsItem[] => { + if (Object.keys(overrides).length > 0) { + const definedFields: string[] = []; + const deleteIndexes: number[] = []; + + // Override current fields' values + data.forEach((item, index) => { + definedFields.push(item.field); + + if (item.field in overrides) { + // If value is undefined, then mark item for deletion + if (!overrides[item.field]) { + deleteIndexes.unshift(index); + } else { + Object.assign(item, overrides[item.field]); + } + } + }); + + // Delete any items from the array + if (deleteIndexes.length > 0) { + for (const index of deleteIndexes) { + data.splice(index, 1); + } + } + + // Add any new fields to the data + Object.entries(overrides).forEach(([field, fieldData]) => { + if (!definedFields.includes(field)) { + data.push({ + category: 'unknown', + field: 'unknonwn', + values: [], + originalValue: [], + isObjectArray: false, + ...fieldData, + }); + } + }); + } + + return data; +}; + +/** @private */ +const generateEndpointAlertDetailsItemDataMock = ( + overrides: AlertDetailsItemDataOverrides = {} +): TimelineEventsDetailsItem[] => { + const data = [ + { + category: 'kibana', + field: 'kibana.alert.rule.uuid', + values: ['b69d086c-325a-4f46-b17b-fb6d227006ba'], + originalValue: ['b69d086c-325a-4f46-b17b-fb6d227006ba'], + isObjectArray: false, + }, + { + category: 'agent', + field: 'agent.type', + values: ['endpoint'], + originalValue: ['endpoint'], + isObjectArray: false, + }, + { + category: 'agent', + field: 'agent.id', + values: ['abfe4a35-d5b4-42a0-a539-bd054c791769'], + originalValue: ['abfe4a35-d5b4-42a0-a539-bd054c791769'], + isObjectArray: false, + }, + { + category: 'event', + field: 'event.module', + values: ['endpoint'], + originalValue: ['endpoint'], + isObjectArray: false, + }, + { + category: 'event', + field: 'event.category', + originalValue: ['process'], + values: ['process'], + isObjectArray: false, + }, + { + category: 'host', + field: 'host.name', + values: ['elastic-host-win'], + originalValue: ['windows-native'], + isObjectArray: false, + }, + { + category: 'host', + field: 'host.os.family', + values: ['windows'], + originalValue: ['windows'], + isObjectArray: false, + }, + ]; + + setAlertDetailsItemDataOverrides(data, overrides); + + return data; +}; + +/** @private */ +const generateSentinelOneAlertDetailsItemDataMock = ( + overrides: AlertDetailsItemDataOverrides = {} +): TimelineEventsDetailsItem[] => { + const data = generateEndpointAlertDetailsItemDataMock(overrides); + + data.forEach((itemData) => { + switch (itemData.field) { + case 'event.module': + itemData.values = ['sentinel_one']; + itemData.originalValue = ['sentinel_one']; + break; + + case 'agent.type': + itemData.values = ['filebeat']; + itemData.originalValue = ['filebeat']; + break; + } + }); + + data.push({ + category: 'observer', + field: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one, + values: ['abfe4a35-d5b4-42a0-a539-bd054c791769'], + originalValue: ['abfe4a35-d5b4-42a0-a539-bd054c791769'], + isObjectArray: false, + }); + + setAlertDetailsItemDataOverrides(data, overrides); + + return data; +}; + +/** @private */ +const generateCrowdStrikeAlertDetailsItemDataMock = ( + overrides: AlertDetailsItemDataOverrides = {} +): TimelineEventsDetailsItem[] => { + const data = generateEndpointAlertDetailsItemDataMock(); + + data.forEach((itemData) => { + switch (itemData.field) { + case 'event.module': + itemData.values = ['crowdstrike']; + itemData.originalValue = ['crowdstrike']; + break; + + case 'agent.type': + itemData.values = ['filebeat']; + itemData.originalValue = ['filebeat']; + break; + } + }); + + data.push( + { + category: 'crowdstrike', + field: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.crowdstrike, + values: ['abfe4a35-d5b4-42a0-a539-bd054c791769'], + originalValue: ['abfe4a35-d5b4-42a0-a539-bd054c791769'], + isObjectArray: false, + }, + { + category: 'crowdstrike', + field: 'crowdstrike.event.HostName', + values: ['elastic-host-win'], + originalValue: ['windows-native'], + isObjectArray: false, + }, + { + category: 'crowdstrike', + field: 'crowdstrike.event.Platform', + values: ['windows'], + originalValue: ['windows'], + isObjectArray: false, + } + ); + + setAlertDetailsItemDataOverrides(data, overrides); + + return data; +}; + +/** + * Will return alert details item data for a known agent type or if unknown agent type is + * pass, then data will be for `filebeat` + * @param agentType + * @param overrides + */ +const generateAlertDetailsItemDataForAgentTypeMock = ( + agentType?: ResponseActionAgentType | string, + overrides: AlertDetailsItemDataOverrides = {} +): TimelineEventsDetailsItem[] => { + const unSupportedAgentType = agentType ?? 'filebeat'; + + switch (agentType) { + case 'endpoint': + return generateEndpointAlertDetailsItemDataMock(overrides); + case 'sentinel_one': + return generateSentinelOneAlertDetailsItemDataMock(overrides); + case 'crowdstrike': + return generateCrowdStrikeAlertDetailsItemDataMock(overrides); + default: + return generateEndpointAlertDetailsItemDataMock({ + 'agent.type': { values: [unSupportedAgentType], originalValue: [unSupportedAgentType] }, + 'event.module': { values: [unSupportedAgentType], originalValue: [unSupportedAgentType] }, + ...overrides, + }); + } +}; + +export const endpointAlertDataMock = Object.freeze({ + generateEndpointAlertDetailsItemData: generateEndpointAlertDetailsItemDataMock, + generateSentinelOneAlertDetailsItemData: generateSentinelOneAlertDetailsItemDataMock, + generateCrowdStrikeAlertDetailsItemData: generateCrowdStrikeAlertDetailsItemDataMock, + generateAlertDetailsItemDataForAgentType: generateAlertDetailsItemDataForAgentTypeMock, +}); diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/index.ts b/x-pack/plugins/security_solution/public/common/mock/endpoint/index.ts index 041a8b319ec464..a7d3f604af5623 100644 --- a/x-pack/plugins/security_solution/public/common/mock/endpoint/index.ts +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/index.ts @@ -7,3 +7,5 @@ export * from './dependencies_start_mock'; export * from './app_context_render'; +export * from './endpoint_alert_data_mock'; +export * from './http_handler_mock_factory'; diff --git a/x-pack/plugins/security_solution/public/common/translations.ts b/x-pack/plugins/security_solution/public/common/translations.ts index 9720baa0d5aa0e..dfb4d29f593712 100644 --- a/x-pack/plugins/security_solution/public/common/translations.ts +++ b/x-pack/plugins/security_solution/public/common/translations.ts @@ -101,7 +101,7 @@ export const UNSAVED_TIMELINE_SAVE_PROMPT_TITLE = i18n.translate( } ); -export const getAgentTypeName = (agentType: ResponseActionAgentType) => { +export const getAgentTypeName = (agentType: ResponseActionAgentType): string => { switch (agentType) { case 'endpoint': return 'Elastic Defend'; diff --git a/x-pack/plugins/security_solution/public/common/utils/crowdstrike_alert_check.test.ts b/x-pack/plugins/security_solution/public/common/utils/crowdstrike_alert_check.test.ts deleted file mode 100644 index 3d585808b88858..00000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/crowdstrike_alert_check.test.ts +++ /dev/null @@ -1,69 +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 { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; - -import { - isAlertFromCrowdstrikeAlert, - isAlertFromCrowdstrikeEvent, -} from './crowdstrike_alert_check'; - -describe('crowdstrike_alert_check', () => { - describe('isAlertFromCrowdstrikeEvent', () => { - it('returns false if data is not a timeline event alert', () => { - const data: TimelineEventsDetailsItem[] = []; - expect(isAlertFromCrowdstrikeEvent({ data })).toBe(false); - }); - - it('returns false if data is a timeline event alert but not from Crowdstrike', () => { - const data = [ - { - category: 'kibana', - field: 'kibana.alert.rule.uuid', - }, - ] as unknown as TimelineEventsDetailsItem[]; - expect(isAlertFromCrowdstrikeEvent({ data })).toBe(false); - }); - - it('returns true if data is a Crowdstrike timeline event alert', () => { - const data = [ - { - category: 'kibana', - field: 'kibana.alert.rule.uuid', - }, - { - field: 'event.module', - values: ['crowdstrike'], - }, - ] as unknown as TimelineEventsDetailsItem[]; - expect(isAlertFromCrowdstrikeEvent({ data })).toBe(true); - }); - }); - - describe('isAlertFromCrowdstrikeAlert', () => { - it('returns false if ecsData is null', () => { - expect(isAlertFromCrowdstrikeAlert({ ecsData: null })).toBe(false); - }); - - it('returns false if ecsData is not a Crowdstrike alert', () => { - const ecsData = { - 'kibana.alert.original_event.module': ['other'], - 'kibana.alert.original_event.dataset': ['other'], - } as unknown as Ecs; - expect(isAlertFromCrowdstrikeAlert({ ecsData })).toBe(false); - }); - - it('returns true if ecsData is a Crowdstrike alert', () => { - const ecsData = { - 'kibana.alert.original_event.module': ['crowdstrike'], - 'kibana.alert.original_event.dataset': ['alert'], - } as unknown as Ecs; - expect(isAlertFromCrowdstrikeAlert({ ecsData })).toBe(true); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/common/utils/crowdstrike_alert_check.ts b/x-pack/plugins/security_solution/public/common/utils/crowdstrike_alert_check.ts deleted file mode 100644 index 5bb1befbadd519..00000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/crowdstrike_alert_check.ts +++ /dev/null @@ -1,69 +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 { find, getOr, some } from 'lodash/fp'; -import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; -import { getFieldValue } from '../../detections/components/host_isolation/helpers'; - -/** - * Check to see if a timeline event item is an Alert (vs an event) - * @param timelineEventItem - */ -export const isTimelineEventItemAnAlert = ( - timelineEventItem: TimelineEventsDetailsItem[] -): boolean => { - return some({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, timelineEventItem); -}; - -export const CROWDSTRIKE_AGENT_ID_FIELD = 'crowdstrike.event.DeviceId'; - -export const getCrowdstrikeAgentId = ( - data: TimelineEventsDetailsItem[] | null -): string | undefined => { - return ( - getFieldValue({ category: 'crowdstrike', field: CROWDSTRIKE_AGENT_ID_FIELD }, data) || undefined - ); -}; - -/** - * Checks to see if the given set of Timeline event detail items includes data that indicates its - * an endpoint Alert. Note that it will NOT match on Events - only alerts - * @param data - */ -export const isAlertFromCrowdstrikeEvent = ({ - data, -}: { - data: TimelineEventsDetailsItem[]; -}): boolean => { - if (!isTimelineEventItemAnAlert(data)) { - return false; - } - - const findEndpointAlert = find({ field: 'event.module' }, data)?.values; - return findEndpointAlert ? findEndpointAlert[0] === 'crowdstrike' : false; -}; - -/** - * Checks to see if the given alert was generated out of the Crowdstrike Alerts dataset, coming from - * crowdstrike Fleet integration - * @param ecsData - */ -export const isAlertFromCrowdstrikeAlert = ({ - ecsData, -}: { - ecsData: Ecs | null | undefined; -}): boolean => { - if (ecsData == null) { - return false; - } - - const eventModules = getOr([], 'kibana.alert.original_event.module', ecsData); - const kinds = getOr([], 'kibana.alert.original_event.dataset', ecsData); - - return eventModules.includes('crowdstrike') && kinds.includes('alert'); -}; diff --git a/x-pack/plugins/security_solution/public/common/utils/endpoint_alert_check.test.ts b/x-pack/plugins/security_solution/public/common/utils/endpoint_alert_check.test.ts deleted file mode 100644 index d62347f6790b3e..00000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/endpoint_alert_check.test.ts +++ /dev/null @@ -1,85 +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 _ from 'lodash'; -import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; -import { generateMockDetailItemData } from '../mock'; -import { isAlertFromEndpointAlert, isAlertFromEndpointEvent } from './endpoint_alert_check'; - -describe('isAlertFromEndpointEvent', () => { - let mockDetailItemData: ReturnType; - - beforeEach(() => { - mockDetailItemData = generateMockDetailItemData(); - - // Remove the filebeat agent type from the mock - _.remove(mockDetailItemData, { field: 'agent.type' }); - - mockDetailItemData.push( - // Must be an Alert - { - field: 'kibana.alert.rule.uuid', - category: 'kibana', - originalValue: 'endpoint', - values: ['endpoint'], - isObjectArray: false, - }, - // Must be from an endpoint agent - { - field: 'agent.type', - originalValue: 'endpoint', - values: ['endpoint'], - isObjectArray: false, - } - ); - }); - - it('should return true if detections data comes from an endpoint rule', () => { - expect(isAlertFromEndpointEvent({ data: mockDetailItemData })).toBe(true); - }); - - it('should return false if it is not an Alert (ex. maybe an event)', () => { - _.remove(mockDetailItemData, { field: 'kibana.alert.rule.uuid' }); - expect(isAlertFromEndpointEvent({ data: mockDetailItemData })).toBeFalsy(); - }); - - it('should return false if it is not an endpoint agent', () => { - _.remove(mockDetailItemData, { field: 'agent.type' }); - expect(isAlertFromEndpointEvent({ data: mockDetailItemData })).toBeFalsy(); - }); -}); - -describe('isAlertFromEndpointAlert', () => { - it('should return true if detections data comes from an endpoint rule', () => { - const mockEcsData = { - _id: 'mockId', - 'kibana.alert.original_event.module': ['endpoint'], - 'kibana.alert.original_event.kind': ['alert'], - } as Ecs; - expect(isAlertFromEndpointAlert({ ecsData: mockEcsData })).toBe(true); - }); - - it('should return false if ecsData is undefined', () => { - expect(isAlertFromEndpointAlert({ ecsData: undefined })).toBeFalsy(); - }); - - it('should return false if it is not an Alert', () => { - const mockEcsData = { - _id: 'mockId', - 'kibana.alert.original_event.module': ['endpoint'], - } as Ecs; - expect(isAlertFromEndpointAlert({ ecsData: mockEcsData })).toBeFalsy(); - }); - - it('should return false if it is not an endpoint module', () => { - const mockEcsData = { - _id: 'mockId', - 'kibana.alert.original_event.kind': ['alert'], - } as Ecs; - expect(isAlertFromEndpointAlert({ ecsData: mockEcsData })).toBeFalsy(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/common/utils/endpoint_alert_check.ts b/x-pack/plugins/security_solution/public/common/utils/endpoint_alert_check.ts deleted file mode 100644 index b755094b679d36..00000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/endpoint_alert_check.ts +++ /dev/null @@ -1,53 +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 { find, getOr, some } from 'lodash/fp'; -import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; - -/** - * Check to see if a timeline event item is an Alert (vs an event) - * @param timelineEventItem - */ -export const isTimelineEventItemAnAlert = ( - timelineEventItem: TimelineEventsDetailsItem[] -): boolean => { - return some({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, timelineEventItem); -}; - -/** - * Checks to see if the given set of Timeline event detail items includes data that indicates its - * an endpoint Alert. Note that it will NOT match on Events - only alerts - * @param data - */ -export const isAlertFromEndpointEvent = ({ - data, -}: { - data: TimelineEventsDetailsItem[]; -}): boolean => { - if (!isTimelineEventItemAnAlert(data)) { - return false; - } - - const findEndpointAlert = find({ field: 'agent.type' }, data)?.values; - return findEndpointAlert ? findEndpointAlert[0] === 'endpoint' : false; -}; - -export const isAlertFromEndpointAlert = ({ - ecsData, -}: { - ecsData: Ecs | null | undefined; -}): boolean => { - if (ecsData == null) { - return false; - } - - const eventModules = getOr([], 'kibana.alert.original_event.module', ecsData); - const kinds = getOr([], 'kibana.alert.original_event.kind', ecsData); - - return eventModules.includes('endpoint') && kinds.includes('alert'); -}; diff --git a/x-pack/plugins/security_solution/public/common/utils/sentinelone_alert_check.ts b/x-pack/plugins/security_solution/public/common/utils/sentinelone_alert_check.ts deleted file mode 100644 index b588ba7320144a..00000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/sentinelone_alert_check.ts +++ /dev/null @@ -1,64 +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 { find, getOr, some } from 'lodash/fp'; -import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; -import { getFieldValue } from '../../detections/components/host_isolation/helpers'; - -/** - * Check to see if a timeline event item is an Alert (vs an event) - * @param timelineEventItem - */ -export const isTimelineEventItemAnAlert = ( - timelineEventItem: TimelineEventsDetailsItem[] -): boolean => { - return some({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, timelineEventItem); -}; - -export const SENTINEL_ONE_AGENT_ID_FIELD = 'observer.serial_number'; - -export const getSentinelOneAgentId = (data: TimelineEventsDetailsItem[] | null) => - getFieldValue({ category: 'observer', field: SENTINEL_ONE_AGENT_ID_FIELD }, data) || undefined; - -/** - * Checks to see if the given set of Timeline event detail items includes data that indicates its - * an endpoint Alert. Note that it will NOT match on Events - only alerts - * @param data - */ -export const isAlertFromSentinelOneEvent = ({ - data, -}: { - data: TimelineEventsDetailsItem[]; -}): boolean => { - if (!isTimelineEventItemAnAlert(data)) { - return false; - } - - const findEndpointAlert = find({ field: 'event.module' }, data)?.values; - return findEndpointAlert ? findEndpointAlert[0] === 'sentinel_one' : false; -}; - -/** - * Checks to see if the given alert was generated out of the SentinelOne Alerts dataset, coming from - * sentinel_one Fleet integration - * @param ecsData - */ -export const isAlertFromSentinelOneAlert = ({ - ecsData, -}: { - ecsData: Ecs | null | undefined; -}): boolean => { - if (ecsData == null) { - return false; - } - - const eventModules = getOr([], 'kibana.alert.original_event.module', ecsData); - const kinds = getOr([], 'kibana.alert.original_event.dataset', ecsData); - - return eventModules.includes('sentinel_one') && kinds.includes('alert'); -}; 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 d18a4c5bf658ce..c4afc5ceb5f6a6 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 @@ -11,7 +11,7 @@ import { EuiButtonIcon, EuiContextMenu, EuiPopover, EuiToolTip } from '@elastic/ import { indexOf } from 'lodash'; import { useSelector } from 'react-redux'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; -import { get } from 'lodash/fp'; +import { get, getOr } from 'lodash/fp'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { TableId } from '@kbn/securitysolution-data-table'; import { useRuleWithFallback } from '../../../../detection_engine/rule_management/logic/use_rule_with_fallback'; @@ -46,7 +46,6 @@ import type { import { ATTACH_ALERT_TO_CASE_FOR_ROW } from '../../../../timelines/components/timeline/body/translations'; import { useEventFilterAction } from './use_event_filter_action'; import { useAddToCaseActions } from './use_add_to_case_actions'; -import { isAlertFromEndpointAlert } from '../../../../common/utils/endpoint_alert_check'; import type { Rule } from '../../../../detection_engine/rule_management/logic/types'; import type { AlertTableContextMenuItem } from '../types'; import { useAlertTagsActions } from './use_alert_tags_actions'; @@ -115,6 +114,13 @@ const AlertContextMenuComponent: React.FC = ({ const isEvent = useMemo(() => indexOf(ecsRowData.event?.kind, 'event') !== -1, [ecsRowData]); const isAgentEndpoint = useMemo(() => ecsRowData.agent?.type?.includes('endpoint'), [ecsRowData]); const isEndpointEvent = useMemo(() => isEvent && isAgentEndpoint, [isEvent, isAgentEndpoint]); + const isAlertSourceEndpoint = useMemo(() => { + const eventModules = getOr([], 'kibana.alert.original_event.module', ecsRowData); + const kinds = getOr([], 'kibana.alert.original_event.kind', ecsRowData); + + return eventModules.includes('endpoint') && kinds.includes('alert'); + }, [ecsRowData]); + const scopeIdAllowsAddEndpointEventFilter = useMemo( () => scopeId === TableId.hostsPageEvents || scopeId === TableId.usersPageEvents, [scopeId] @@ -200,7 +206,7 @@ const AlertContextMenuComponent: React.FC = ({ }, [closePopover, onAddEventFilterClick]); const { exceptionActionItems } = useAlertExceptionActions({ - isEndpointAlert: isAlertFromEndpointAlert({ ecsData: ecsRowData }), + isEndpointAlert: isAlertSourceEndpoint, onAddExceptionTypeClick: handleOnAddExceptionTypeClick, }); const { eventFilterActionItems } = useEventFilterAction({ diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/get_external_edr_agent_info.test.ts b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/get_external_edr_agent_info.test.ts deleted file mode 100644 index 9e20b45f55fe6f..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/get_external_edr_agent_info.test.ts +++ /dev/null @@ -1,120 +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 { getSentinelOneAgentId } from '../../../common/utils/sentinelone_alert_check'; -import { getCrowdstrikeAgentId } from '../../../common/utils/crowdstrike_alert_check'; -import { getExternalEdrAgentInfo } from './get_external_edr_agent_info'; - -jest.mock('../../../common/utils/sentinelone_alert_check'); -jest.mock('../../../common/utils/crowdstrike_alert_check'); - -describe('getExternalEdrAgentInfo', () => { - const mockEventData = [ - { - category: 'event', - field: 'event.module', - values: ['sentinel_one'], - isObjectArray: false, - }, - { - category: 'host', - field: 'host.name', - values: ['test-host'], - isObjectArray: false, - }, - { - category: 'host', - field: 'host.os.name', - values: ['Windows'], - isObjectArray: false, - }, - { - category: 'host', - field: 'host.os.family', - values: ['windows'], - isObjectArray: false, - }, - { - category: 'host', - field: 'host.os.version', - values: ['10'], - isObjectArray: false, - }, - { - category: 'kibana', - field: 'kibana.alert.last_detected', - values: ['2023-05-01T12:34:56Z'], - isObjectArray: false, - }, - { - category: 'crowdstrike', - field: 'crowdstrike.event.HostName', - values: ['test-crowdstrike-host'], - isObjectArray: false, - }, - { - category: 'crowdstrike', - field: 'crowdstrike.event.Platform', - values: ['linux'], - isObjectArray: false, - }, - ]; - - beforeEach(() => { - (getSentinelOneAgentId as jest.Mock).mockReturnValue('sentinel-one-agent-id'); - (getCrowdstrikeAgentId as jest.Mock).mockReturnValue('crowdstrike-agent-id'); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should return correct info for sentinel_one agent type', () => { - const result = getExternalEdrAgentInfo(mockEventData, 'sentinel_one'); - expect(result).toEqual({ - agent: { - id: 'sentinel-one-agent-id', - type: 'sentinel_one', - }, - host: { - name: 'test-host', - os: { - name: 'Windows', - family: 'windows', - version: '10', - }, - }, - lastCheckin: '2023-05-01T12:34:56Z', - }); - }); - - it('should return correct info for crowdstrike agent type', () => { - const result = getExternalEdrAgentInfo(mockEventData, 'crowdstrike'); - expect(result).toEqual({ - agent: { - id: 'crowdstrike-agent-id', - type: 'crowdstrike', - }, - host: { - name: 'test-crowdstrike-host', - os: { - name: '', - family: 'linux', - version: '', - }, - }, - lastCheckin: '2023-05-01T12:34:56Z', - }); - }); - - it('should throw an error for unsupported agent type', () => { - expect(() => { - // @ts-expect-error testing purpose - getExternalEdrAgentInfo(mockEventData, 'unsupported_agent_type'); - }).toThrow('Unsupported agent type: unsupported_agent_type'); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/get_external_edr_agent_info.ts b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/get_external_edr_agent_info.ts deleted file mode 100644 index 0c9c9ed9f0138f..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/get_external_edr_agent_info.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; -import type { ThirdPartyAgentInfo } from '../../../../common/types'; -import { getSentinelOneAgentId } from '../../../common/utils/sentinelone_alert_check'; -import { getFieldValue } from '../host_isolation/helpers'; -import { getCrowdstrikeAgentId } from '../../../common/utils/crowdstrike_alert_check'; - -export const getExternalEdrAgentInfo = ( - eventData: TimelineEventsDetailsItem[], - agentType: ResponseActionAgentType -): ThirdPartyAgentInfo => { - switch (agentType) { - case 'sentinel_one': - return { - agent: { - id: getSentinelOneAgentId(eventData) || '', - type: getFieldValue( - { category: 'event', field: 'event.module' }, - eventData - ) as ResponseActionAgentType, - }, - host: { - name: getFieldValue({ category: 'host', field: 'host.name' }, eventData), - os: { - name: getFieldValue({ category: 'host', field: 'host.os.name' }, eventData), - family: getFieldValue({ category: 'host', field: 'host.os.family' }, eventData), - version: getFieldValue({ category: 'host', field: 'host.os.version' }, eventData), - }, - }, - lastCheckin: getFieldValue( - { category: 'kibana', field: 'kibana.alert.last_detected' }, - eventData - ), - }; - case 'crowdstrike': - return { - agent: { - id: getCrowdstrikeAgentId(eventData) || '', - type: agentType, - }, - host: { - name: getFieldValue( - { category: 'crowdstrike', field: 'crowdstrike.event.HostName' }, - eventData - ), - os: { - name: '', - family: getFieldValue( - { category: 'crowdstrike', field: 'crowdstrike.event.Platform' }, - eventData - ), - version: '', - }, - }, - lastCheckin: getFieldValue( - { category: 'kibana', field: 'kibana.alert.last_detected' }, - eventData - ), - }; - default: - throw new Error(`Unsupported agent type: ${agentType}`); - } -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.test.ts b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.test.ts deleted file mode 100644 index 76be881fa553d0..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.test.ts +++ /dev/null @@ -1,233 +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 { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; -import { useResponderActionData } from './use_responder_action_data'; -import { renderHook } from '@testing-library/react-hooks'; -import { useGetEndpointDetails } from '../../../management/hooks'; -import { HostStatus } from '../../../../common/endpoint/types'; -import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import { HOST_ENDPOINT_UNENROLLED_TOOLTIP } from './translations'; - -jest.mock('../../../common/hooks/use_experimental_features'); -jest.mock('../../../management/hooks', () => ({ - useGetEndpointDetails: (jest.fn() as jest.Mock).mockImplementation(() => ({ enabled: false })), - useWithShowResponder: jest.fn(), -})); - -const useGetEndpointDetailsMock = useGetEndpointDetails as jest.Mock; -const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; - -describe('#useResponderActionData', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should return `responder` menu item as `disabled` if agentType is not `endpoint` and feature flag is enabled', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(false); - - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'some-agent-type-id', - // @ts-expect-error this is for testing purpose - agentType: 'some_agent_type', - eventData: [], - }) - ); - expect(result.current.isDisabled).toEqual(true); - }); - - describe('when agentType is `endpoint`', () => { - it.each(Object.values(HostStatus).filter((status) => status !== 'unenrolled'))( - 'should return `responder` menu item as `enabled `if agentType is `endpoint` when endpoint is %s', - (hostStatus) => { - useGetEndpointDetailsMock.mockReturnValue({ - data: { - host_status: hostStatus, - }, - isFetching: false, - error: undefined, - }); - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'endpoint-id', - agentType: 'endpoint', - }) - ); - expect(result.current.isDisabled).toEqual(false); - } - ); - - it('should return responder menu item `disabled` if agentType is `endpoint` when endpoint is `unenrolled`', () => { - useGetEndpointDetailsMock.mockReturnValue({ - data: { - host_status: 'unenrolled', - }, - isFetching: false, - error: undefined, - }); - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'endpoint-id', - agentType: 'endpoint', - }) - ); - expect(result.current.isDisabled).toEqual(true); - }); - - it('should return responder menu item `disabled` if agentType is `endpoint` when endpoint data has error', () => { - useGetEndpointDetailsMock.mockReturnValue({ - data: { - host_status: 'online', - }, - isFetching: false, - error: new Error('uh oh!'), - }); - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'endpoint-id', - agentType: 'endpoint', - }) - ); - expect(result.current.isDisabled).toEqual(true); - }); - - it('should return responder menu item `disabled` if agentType is `endpoint` and endpoint data is fetching', () => { - useGetEndpointDetailsMock.mockReturnValue({ - data: undefined, - isFetching: true, - error: undefined, - }); - - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'endpoint-id', - agentType: 'endpoint', - }) - ); - expect(result.current.isDisabled).toEqual(true); - }); - - it('should return responder menu item `disabled` when agentType is `endpoint` but no endpoint id is provided', () => { - const { result } = renderHook(() => - useResponderActionData({ - endpointId: '', - agentType: 'endpoint', - }) - ); - expect(result.current.isDisabled).toEqual(true); - expect(result.current.tooltip).toEqual(HOST_ENDPOINT_UNENROLLED_TOOLTIP); - }); - }); - - describe('when agentType is `sentinel_one`', () => { - const createEventDataMock = (): TimelineEventsDetailsItem[] => { - return [ - { - category: 'observer', - field: 'observer.serial_number', - values: ['c06d63d9-9fa2-046d-e91e-dc94cf6695d8'], - originalValue: ['c06d63d9-9fa2-046d-e91e-dc94cf6695d8'], - isObjectArray: false, - }, - ]; - }; - - it('should return `responder` menu item as `disabled` if agentType is `sentinel_one` and feature flag is disabled', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(false); - - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'sentinel-one-id', - agentType: 'sentinel_one', - eventData: createEventDataMock(), - }) - ); - expect(result.current.isDisabled).toEqual(true); - }); - - it('should return responder menu item as disabled with tooltip if agent id property is missing from event data', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(true); - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'sentinel-one-id', - agentType: 'sentinel_one', - eventData: [], - }) - ); - expect(result.current.isDisabled).toEqual(true); - expect(result.current.tooltip).toEqual( - 'Event data missing SentinelOne agent identifier (observer.serial_number)' - ); - }); - - it('should return `responder` menu item as `enabled `if agentType is `sentinel_one` and feature flag is enabled', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(true); - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'sentinel-one-id', - agentType: 'sentinel_one', - eventData: createEventDataMock(), - }) - ); - expect(result.current.isDisabled).toEqual(false); - }); - }); - describe('when agentType is `crowdstrike`', () => { - const createEventDataMock = (): TimelineEventsDetailsItem[] => { - return [ - { - category: 'crowdstrike', - field: 'crowdstrike.event.DeviceId', - values: ['mockedAgentId'], - originalValue: ['mockedAgentId'], - isObjectArray: false, - }, - ]; - }; - - it('should return `responder` menu item as `disabled` if agentType is `crowdstrike` and feature flag is disabled', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(false); - - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'crowdstrike-id', - agentType: 'crowdstrike', - eventData: createEventDataMock(), - }) - ); - expect(result.current.isDisabled).toEqual(true); - }); - - it('should return responder menu item as disabled with tooltip if agent id property is missing from event data', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(true); - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'crowdstrike-id', - agentType: 'crowdstrike', - eventData: [], - }) - ); - expect(result.current.isDisabled).toEqual(true); - expect(result.current.tooltip).toEqual( - 'Event data missing Crowdstrike agent identifier (crowdstrike.event.DeviceId)' - ); - }); - - it('should return `responder` menu item as `enabled `if agentType is `crowdstrike` and feature flag is enabled', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(true); - const { result } = renderHook(() => - useResponderActionData({ - endpointId: 'crowdstrike-id', - agentType: 'crowdstrike', - eventData: createEventDataMock(), - }) - ); - expect(result.current.isDisabled).toEqual(false); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.ts b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.ts deleted file mode 100644 index b2bf6d22643f46..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.ts +++ /dev/null @@ -1,175 +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 { ReactNode } from 'react'; -import { useCallback, useMemo } from 'react'; -import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import { getExternalEdrAgentInfo } from './get_external_edr_agent_info'; -import { getCrowdstrikeAgentId } from '../../../common/utils/crowdstrike_alert_check'; -import type { Platform } from '../../../management/components/endpoint_responder/components/header_info/platforms'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; -import { getSentinelOneAgentId } from '../../../common/utils/sentinelone_alert_check'; -import type { - ResponseActionAgentType, - EndpointCapabilities, -} from '../../../../common/endpoint/service/response_actions/constants'; -import { useGetEndpointDetails, useWithShowResponder } from '../../../management/hooks'; -import { HostStatus } from '../../../../common/endpoint/types'; -import { - CROWDSTRIKE_AGENT_ID_PROPERTY_MISSING, - HOST_ENDPOINT_UNENROLLED_TOOLTIP, - LOADING_ENDPOINT_DATA_TOOLTIP, - METADATA_API_ERROR_TOOLTIP, - NOT_FROM_ENDPOINT_HOST_TOOLTIP, - SENTINEL_ONE_AGENT_ID_PROPERTY_MISSING, -} from './translations'; - -export interface ResponderContextMenuItemProps { - endpointId: string; - onClick?: () => void; - agentType: ResponseActionAgentType; - eventData?: TimelineEventsDetailsItem[] | null; -} - -/** - * This hook is used to get the data needed to show the context menu items for the responder - * actions. - * @param endpointId the id of the endpoint - * @param onClick the callback to handle the click event - * @param agentType the type of agent, defaults to 'endpoint' - * @param eventData the event data, exists only when agentType !== 'endpoint' - * @returns an object with the data needed to show the context menu item - */ - -export const useResponderActionData = ({ - endpointId, - onClick, - agentType, - eventData, -}: ResponderContextMenuItemProps): { - handleResponseActionsClick: () => void; - isDisabled: boolean; - tooltip: ReactNode; -} => { - const isEndpointHost = agentType === 'endpoint'; - const showResponseActionsConsole = useWithShowResponder(); - - const isSentinelOneV1Enabled = useIsExperimentalFeatureEnabled( - 'responseActionsSentinelOneV1Enabled' - ); - const responseActionsCrowdstrikeManualHostIsolationEnabled = useIsExperimentalFeatureEnabled( - 'responseActionsCrowdstrikeManualHostIsolationEnabled' - ); - const { - data: hostInfo, - isFetching, - error, - } = useGetEndpointDetails(endpointId, { enabled: Boolean(endpointId && isEndpointHost) }); - - const [isDisabled, tooltip]: [disabled: boolean, tooltip: ReactNode] = useMemo(() => { - // v8.13 disabled for third-party agent alerts if the feature flag is not enabled - if (!isEndpointHost) { - switch (agentType) { - case 'sentinel_one': - // Disable it if feature flag is disabled - if (!isSentinelOneV1Enabled) { - return [true, undefined]; - } - // Event must have the property that identifies the agent id - if (!getSentinelOneAgentId(eventData ?? null)) { - return [true, SENTINEL_ONE_AGENT_ID_PROPERTY_MISSING]; - } - - return [false, undefined]; - case 'crowdstrike': - // Disable it if feature flag is disabled - if (!responseActionsCrowdstrikeManualHostIsolationEnabled) { - return [true, undefined]; - } - // Event must have the property that identifies the agent id - if (!getCrowdstrikeAgentId(eventData ?? null)) { - return [true, CROWDSTRIKE_AGENT_ID_PROPERTY_MISSING]; - } - - return [false, undefined]; - - default: - return [true, undefined]; - } - } - - if (!endpointId) { - return [true, HOST_ENDPOINT_UNENROLLED_TOOLTIP]; - } - - // Still loading host info - if (isFetching) { - return [true, LOADING_ENDPOINT_DATA_TOOLTIP]; - } - - // if we got an error, and it's a 404, it means the endpoint is not from the endpoint host - if (error && error.body?.statusCode === 404) { - return [true, NOT_FROM_ENDPOINT_HOST_TOOLTIP]; - } - - // if we got an error and, - // it's a 400 with unenrolled in the error message (alerts can exist for endpoint that are no longer around) - // or, - // the Host status is `unenrolled` - if ( - (error && error.body?.statusCode === 400 && error.body?.message.includes('unenrolled')) || - hostInfo?.host_status === HostStatus.UNENROLLED - ) { - return [true, HOST_ENDPOINT_UNENROLLED_TOOLTIP]; - } - - // return general error tooltip - if (error) { - return [true, METADATA_API_ERROR_TOOLTIP]; - } - - return [false, undefined]; - }, [ - isEndpointHost, - endpointId, - isFetching, - error, - hostInfo?.host_status, - agentType, - isSentinelOneV1Enabled, - eventData, - responseActionsCrowdstrikeManualHostIsolationEnabled, - ]); - - const handleResponseActionsClick = useCallback(() => { - if (!isEndpointHost && eventData != null) { - const agentInfoFromAlert = getExternalEdrAgentInfo(eventData, agentType); - showResponseActionsConsole({ - agentId: agentInfoFromAlert.agent.id, - agentType, - capabilities: ['isolation'], - hostName: agentInfoFromAlert.host.name, - platform: agentInfoFromAlert.host.os.family, - }); - } - if (isEndpointHost && hostInfo) { - showResponseActionsConsole({ - agentId: hostInfo.metadata.agent.id, - agentType, - capabilities: (hostInfo.metadata.Endpoint.capabilities as EndpointCapabilities[]) ?? [], - hostName: hostInfo.metadata.host.name, - platform: hostInfo.metadata.host.os.name.toLowerCase() as Platform, - }); - } - if (onClick) onClick(); - }, [isEndpointHost, hostInfo, onClick, eventData, showResponseActionsConsole, agentType]); - - return { - handleResponseActionsClick, - isDisabled, - tooltip, - }; -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.test.tsx b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.test.tsx deleted file mode 100644 index 750a6279851926..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.test.tsx +++ /dev/null @@ -1,144 +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 { renderHook } from '@testing-library/react-hooks'; -import { useResponderActionItem } from './use_responder_action_item'; -import { useUserPrivileges } from '../../../common/components/user_privileges'; -import { isTimelineEventItemAnAlert } from '../../../common/utils/endpoint_alert_check'; -import { getFieldValue } from '../host_isolation/helpers'; -import { isAlertFromCrowdstrikeEvent } from '../../../common/utils/crowdstrike_alert_check'; -import { isAlertFromSentinelOneEvent } from '../../../common/utils/sentinelone_alert_check'; -import { useResponderActionData } from './use_responder_action_data'; - -jest.mock('../../../common/components/user_privileges'); -jest.mock('../../../common/utils/endpoint_alert_check'); -jest.mock('../host_isolation/helpers'); -jest.mock('../../../common/utils/crowdstrike_alert_check'); -jest.mock('../../../common/utils/sentinelone_alert_check'); -jest.mock('./use_responder_action_data'); - -describe('useResponderActionItem', () => { - const mockUseUserPrivileges = useUserPrivileges as jest.Mock; - const mockIsTimelineEventItemAnAlert = isTimelineEventItemAnAlert as jest.Mock; - const mockGetFieldValue = getFieldValue as jest.Mock; - const mockIsAlertFromCrowdstrikeEvent = isAlertFromCrowdstrikeEvent as jest.Mock; - const mockIsAlertFromSentinelOneEvent = isAlertFromSentinelOneEvent as jest.Mock; - const mockUseResponderActionData = useResponderActionData as jest.Mock; - - beforeEach(() => { - jest.clearAllMocks(); - mockUseResponderActionData.mockImplementation(() => ({ - handleResponseActionsClick: jest.fn(), - isDisabled: false, - tooltip: 'Tooltip text', - })); - }); - - it('should return an empty array if user privileges are loading', () => { - mockUseUserPrivileges.mockReturnValue({ - endpointPrivileges: { - loading: true, - canAccessResponseConsole: false, - }, - }); - - const { result } = renderHook(() => useResponderActionItem(null, jest.fn())); - expect(result.current).toEqual([]); - }); - - it('should return an empty array if user cannot access response console', () => { - mockUseUserPrivileges.mockReturnValue({ - endpointPrivileges: { - loading: false, - canAccessResponseConsole: false, - }, - }); - - const { result } = renderHook(() => useResponderActionItem(null, jest.fn())); - expect(result.current).toEqual([]); - }); - - it('should return an empty array if the event is not an alert', () => { - mockUseUserPrivileges.mockReturnValue({ - endpointPrivileges: { - loading: false, - canAccessResponseConsole: true, - }, - }); - mockIsTimelineEventItemAnAlert.mockReturnValue(false); - - const { result } = renderHook(() => useResponderActionItem(null, jest.fn())); - expect(result.current).toEqual([]); - }); - - it('should return the response action item if all conditions are met for a generic endpoint', () => { - mockUseUserPrivileges.mockReturnValue({ - endpointPrivileges: { - loading: false, - canAccessResponseConsole: true, - }, - }); - mockIsTimelineEventItemAnAlert.mockReturnValue(true); - mockGetFieldValue.mockReturnValue('endpoint-id'); - mockIsAlertFromCrowdstrikeEvent.mockReturnValue(false); - mockIsAlertFromSentinelOneEvent.mockReturnValue(false); - - renderHook(() => useResponderActionItem([], jest.fn())); - - expect(mockUseResponderActionData).toHaveBeenCalledWith({ - agentType: 'endpoint', - endpointId: 'endpoint-id', - eventData: null, - onClick: expect.any(Function), - }); - }); - - it('should return the response action item if all conditions are met for a Crowdstrike event', () => { - mockUseUserPrivileges.mockReturnValue({ - endpointPrivileges: { - loading: false, - canAccessResponseConsole: true, - }, - }); - mockIsTimelineEventItemAnAlert.mockReturnValue(true); - mockGetFieldValue.mockReturnValue('crowdstrike-id'); - mockIsAlertFromCrowdstrikeEvent.mockReturnValue(true); - mockIsAlertFromSentinelOneEvent.mockReturnValue(false); - - renderHook(() => useResponderActionItem([], jest.fn())); - - expect(mockUseResponderActionData).toHaveBeenCalledWith({ - agentType: 'crowdstrike', - endpointId: 'crowdstrike-id', - eventData: [], - onClick: expect.any(Function), - }); - }); - - it('should return the response action item if all conditions are met for a SentinelOne event', () => { - mockUseUserPrivileges.mockReturnValue({ - endpointPrivileges: { - loading: false, - canAccessResponseConsole: true, - }, - }); - - mockIsTimelineEventItemAnAlert.mockReturnValue(true); - mockGetFieldValue.mockReturnValue('sentinelone-id'); - mockIsAlertFromCrowdstrikeEvent.mockReturnValue(false); - mockIsAlertFromSentinelOneEvent.mockReturnValue(true); - - renderHook(() => useResponderActionItem([], jest.fn())); - - expect(mockUseResponderActionData).toHaveBeenCalledWith({ - agentType: 'sentinel_one', - endpointId: 'sentinelone-id', - eventData: [], - onClick: expect.any(Function), - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx deleted file mode 100644 index 918de21b704f88..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx +++ /dev/null @@ -1,94 +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, { useMemo } from 'react'; -import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; -import { getSentinelOneAgentId } from '../../../common/utils/sentinelone_alert_check'; -import { getCrowdstrikeAgentId } from '../../../common/utils/crowdstrike_alert_check'; -import { useCasesFromAlerts } from '../../containers/detection_engine/alerts/use_cases_from_alerts'; -import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; -import { getFieldValue } from './helpers'; -import { IsolateHost } from './isolate'; -import { UnisolateHost } from './unisolate'; - -export const HostIsolationPanel = React.memo( - ({ - details, - cancelCallback, - successCallback, - isolateAction, - }: { - details: TimelineEventsDetailsItem[] | null; - cancelCallback: () => void; - successCallback?: () => void; - isolateAction: string; - }) => { - const elasticAgentId = useMemo( - () => getFieldValue({ category: 'agent', field: 'agent.id' }, details), - [details] - ); - - const sentinelOneAgentId = useMemo(() => getSentinelOneAgentId(details), [details]); - const crowdstrikeAgentId = useMemo(() => getCrowdstrikeAgentId(details), [details]); - - const alertId = useMemo( - () => getFieldValue({ category: '_id', field: '_id' }, details), - [details] - ); - - const { casesInfo } = useCasesFromAlerts({ alertId }); - - const agentType: ResponseActionAgentType = useMemo(() => { - if (sentinelOneAgentId) { - return 'sentinel_one'; - } else if (crowdstrikeAgentId) { - return 'crowdstrike'; - } else { - return 'endpoint'; - } - }, [sentinelOneAgentId, crowdstrikeAgentId]); - - const endpointId = useMemo( - () => sentinelOneAgentId ?? crowdstrikeAgentId ?? elasticAgentId, - [elasticAgentId, sentinelOneAgentId, crowdstrikeAgentId] - ); - - const hostName = useMemo(() => { - switch (agentType) { - case 'crowdstrike': - return getFieldValue( - { category: 'crowdstrike', field: 'crowdstrike.event.HostName' }, - details - ); - default: - return getFieldValue({ category: 'host', field: 'host.name' }, details); - } - }, [agentType, details]); - - return isolateAction === 'isolateHost' ? ( - - ) : ( - - ); - } -); - -HostIsolationPanel.displayName = 'HostIsolationContent'; diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.test.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.test.tsx deleted file mode 100644 index 5adbbe58de1674..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.test.tsx +++ /dev/null @@ -1,163 +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 { FC, PropsWithChildren } from 'react'; -import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; -import { useHostIsolationAction } from './use_host_isolation_action'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { - useAgentStatusHook, - useGetAgentStatus, - useGetSentinelOneAgentStatus, -} from '../../../management/hooks/agents/use_get_agent_status'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; -import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; - -jest.mock('../../../management/hooks/agents/use_get_agent_status'); -jest.mock('../../../common/hooks/use_experimental_features'); - -const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; -const useGetSentinelOneAgentStatusMock = useGetSentinelOneAgentStatus as jest.Mock; -const useGetAgentStatusMock = useGetAgentStatus as jest.Mock; -const useAgentStatusHookMock = useAgentStatusHook as jest.Mock; - -describe('useHostIsolationAction', () => { - describe.each([ - ['useGetSentinelOneAgentStatus', useGetSentinelOneAgentStatusMock], - ['useGetAgentStatus', useGetAgentStatusMock], - ])('works with %s hook', (name, hook) => { - const createReactQueryWrapper = () => { - const queryClient = new QueryClient(); - const wrapper: FC> = ({ children }) => ( - {children} - ); - return wrapper; - }; - - const render = (agentTypeAlert: ResponseActionAgentType) => - renderHook( - () => - useHostIsolationAction({ - closePopover: jest.fn(), - detailsData: - agentTypeAlert === 'sentinel_one' - ? [ - { - category: 'kibana', - field: 'kibana.alert.rule.uuid', - isObjectArray: false, - values: ['ruleId'], - originalValue: ['ruleId'], - }, - { - category: 'event', - field: 'event.module', - values: ['sentinel_one'], - originalValue: ['sentinel_one'], - isObjectArray: false, - }, - { - category: 'observer', - field: 'observer.serial_number', - values: ['some-agent-id'], - originalValue: ['some-agent-id'], - isObjectArray: false, - }, - ] - : agentTypeAlert === 'crowdstrike' - ? [ - { - category: 'kibana', - field: 'kibana.alert.rule.uuid', - isObjectArray: false, - values: ['ruleId'], - originalValue: ['ruleId'], - }, - { - category: 'event', - field: 'event.module', - values: ['crowdstrike'], - originalValue: ['crowdstrike'], - isObjectArray: false, - }, - { - category: 'crowdstrike', - field: 'crowdstrike.event.DeviceId', - values: ['expectedCrowdstrikeAgentId'], - originalValue: ['expectedCrowdstrikeAgentId'], - isObjectArray: false, - }, - ] - : [ - { - category: 'agent', - field: 'agent.id', - values: ['some-agent-id'], - originalValue: ['some-agent-id'], - isObjectArray: false, - }, - ], - isHostIsolationPanelOpen: false, - onAddIsolationStatusClick: jest.fn(), - }), - { - wrapper: createReactQueryWrapper(), - } - ); - - beforeEach(() => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(true); - useAgentStatusHookMock.mockImplementation(() => hook); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it(`${name} is invoked as 'enabled' when SentinelOne alert and FF enabled`, () => { - render('sentinel_one'); - - expect(hook).toHaveBeenCalledWith(['some-agent-id'], 'sentinel_one', { - enabled: true, - }); - }); - it(`${name} is invoked as 'enabled' when Crowdstrike alert and FF enabled`, () => { - render('crowdstrike'); - - expect(hook).toHaveBeenCalledWith(['expectedCrowdstrikeAgentId'], 'crowdstrike', { - enabled: true, - }); - }); - - it(`${name} is invoked as 'disabled' when SentinelOne alert and FF disabled`, () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(false); - render('sentinel_one'); - - expect(hook).toHaveBeenCalledWith(['some-agent-id'], 'sentinel_one', { - enabled: false, - }); - }); - - it(`${name} is invoked as 'disabled' when Crowdstrike alert and FF disabled`, () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(false); - render('crowdstrike'); - - expect(hook).toHaveBeenCalledWith(['expectedCrowdstrikeAgentId'], 'crowdstrike', { - enabled: false, - }); - }); - - it(`${name} is invoked as 'disabled' when endpoint alert`, () => { - render('endpoint'); - - expect(hook).toHaveBeenCalledWith([''], 'endpoint', { - enabled: false, - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx deleted file mode 100644 index abafc59bef1952..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx +++ /dev/null @@ -1,272 +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 { useCallback, useMemo } from 'react'; -import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import { useKibana } from '../../../common/lib/kibana/kibana_react'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; -import { - getSentinelOneAgentId, - isAlertFromSentinelOneEvent, -} from '../../../common/utils/sentinelone_alert_check'; -import { - getCrowdstrikeAgentId, - isAlertFromCrowdstrikeEvent, -} from '../../../common/utils/crowdstrike_alert_check'; -import { isIsolationSupported } from '../../../../common/endpoint/service/host_isolation/utils'; -import type { AgentStatusInfo } from '../../../../common/endpoint/types'; -import { HostStatus } from '../../../../common/endpoint/types'; -import { isAlertFromEndpointEvent } from '../../../common/utils/endpoint_alert_check'; -import { useEndpointHostIsolationStatus } from '../../containers/detection_engine/alerts/use_host_isolation_status'; -import { ISOLATE_HOST, UNISOLATE_HOST } from './translations'; -import { getFieldValue } from './helpers'; -import { useUserPrivileges } from '../../../common/components/user_privileges'; -import type { AlertTableContextMenuItem } from '../alerts_table/types'; -import { useAgentStatusHook } from '../../../management/hooks/agents/use_get_agent_status'; - -interface UseHostIsolationActionProps { - closePopover: () => void; - detailsData: TimelineEventsDetailsItem[] | null; - isHostIsolationPanelOpen: boolean; - onAddIsolationStatusClick: (action: 'isolateHost' | 'unisolateHost') => void; -} - -export const useHostIsolationAction = ({ - closePopover, - detailsData, - isHostIsolationPanelOpen, - onAddIsolationStatusClick, -}: UseHostIsolationActionProps): AlertTableContextMenuItem[] => { - const useAgentStatus = useAgentStatusHook(); - - const hasActionsAllPrivileges = useKibana().services.application?.capabilities?.actions?.save; - - const agentStatusClientEnabled = useIsExperimentalFeatureEnabled('agentStatusClientEnabled'); - const sentinelOneManualHostActionsEnabled = useIsExperimentalFeatureEnabled( - 'sentinelOneManualHostActionsEnabled' - ); - const crowdstrikeManualHostActionsEnabled = useIsExperimentalFeatureEnabled( - 'responseActionsCrowdstrikeManualHostIsolationEnabled' - ); - - const { canIsolateHost, canUnIsolateHost } = useUserPrivileges().endpointPrivileges; - - const isEndpointAlert = useMemo( - () => isAlertFromEndpointEvent({ data: detailsData || [] }), - [detailsData] - ); - - const isSentinelOneAlert = useMemo( - () => isAlertFromSentinelOneEvent({ data: detailsData || [] }), - [detailsData] - ); - - const isCrowdstrikeAlert = useMemo( - () => isAlertFromCrowdstrikeEvent({ data: detailsData || [] }), - [detailsData] - ); - - const agentId = useMemo( - () => getFieldValue({ category: 'agent', field: 'agent.id' }, detailsData), - [detailsData] - ); - - const sentinelOneAgentId = useMemo(() => getSentinelOneAgentId(detailsData), [detailsData]); - const crowdstrikeAgentId = useMemo(() => getCrowdstrikeAgentId(detailsData), [detailsData]); - - const externalAgentId = sentinelOneAgentId ?? crowdstrikeAgentId ?? ''; - const hostOsFamily = useMemo( - () => getFieldValue({ category: 'host', field: 'host.os.name' }, detailsData), - [detailsData] - ); - - const agentVersion = useMemo( - () => getFieldValue({ category: 'agent', field: 'agent.version' }, detailsData), - [detailsData] - ); - - const agentType = useMemo(() => { - if (isSentinelOneAlert) { - return 'sentinel_one'; - } - if (isCrowdstrikeAlert) { - return 'crowdstrike'; - } - return 'endpoint'; - }, [isCrowdstrikeAlert, isSentinelOneAlert]); - - const { - loading: loadingHostIsolationStatus, - isIsolated, - agentStatus, - capabilities, - } = useEndpointHostIsolationStatus({ - agentId, - agentType, - }); - - const { data: externalAgentData } = useAgentStatus([externalAgentId], agentType, { - enabled: - (!!sentinelOneAgentId && sentinelOneManualHostActionsEnabled) || - (!!crowdstrikeAgentId && crowdstrikeManualHostActionsEnabled), - }); - - const externalAgentStatus = externalAgentData?.[externalAgentId]; - - const isHostIsolated = useMemo(() => { - if ( - (sentinelOneManualHostActionsEnabled && isSentinelOneAlert) || - (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAlert) - ) { - return externalAgentStatus?.isolated; - } - - return isIsolated; - }, [ - isIsolated, - isSentinelOneAlert, - isCrowdstrikeAlert, - externalAgentStatus?.isolated, - sentinelOneManualHostActionsEnabled, - crowdstrikeManualHostActionsEnabled, - ]); - - const doesHostSupportIsolation = useMemo(() => { - if (isEndpointAlert) { - return isIsolationSupported({ - osName: hostOsFamily, - version: agentVersion, - capabilities, - }); - } - - if ( - (externalAgentStatus && sentinelOneManualHostActionsEnabled && isSentinelOneAlert) || - (externalAgentStatus && crowdstrikeManualHostActionsEnabled && isCrowdstrikeAlert) - ) { - return externalAgentStatus.status === 'healthy'; - } - - return false; - }, [ - isEndpointAlert, - sentinelOneManualHostActionsEnabled, - isSentinelOneAlert, - externalAgentStatus, - crowdstrikeManualHostActionsEnabled, - isCrowdstrikeAlert, - hostOsFamily, - agentVersion, - capabilities, - ]); - - const isolateHostHandler = useCallback(() => { - closePopover(); - if (!isHostIsolated) { - onAddIsolationStatusClick('isolateHost'); - } else { - onAddIsolationStatusClick('unisolateHost'); - } - }, [closePopover, isHostIsolated, onAddIsolationStatusClick]); - - const isIsolationActionDisabled = useMemo(() => { - if ( - (sentinelOneManualHostActionsEnabled && isSentinelOneAlert) || - (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAlert) - ) { - // 8.15 use FF for computing if action is enabled - if (agentStatusClientEnabled) { - return externalAgentStatus?.status === HostStatus.UNENROLLED; - } - - // else use the old way - if (!externalAgentStatus) { - return true; - } - - const { isUninstalled, isPendingUninstall } = externalAgentStatus as AgentStatusInfo[string]; - - return isUninstalled || isPendingUninstall; - } - - return agentStatus === HostStatus.UNENROLLED; - }, [ - agentStatus, - agentStatusClientEnabled, - isSentinelOneAlert, - externalAgentStatus, - sentinelOneManualHostActionsEnabled, - crowdstrikeManualHostActionsEnabled, - isCrowdstrikeAlert, - ]); - - const menuItems = useMemo( - () => [ - { - key: 'isolate-host-action-item', - 'data-test-subj': 'isolate-host-action-item', - disabled: isIsolationActionDisabled, - onClick: isolateHostHandler, - name: isHostIsolated ? UNISOLATE_HOST : ISOLATE_HOST, - }, - ], - [isHostIsolated, isolateHostHandler, isIsolationActionDisabled] - ); - - return useMemo(() => { - if (isHostIsolationPanelOpen) { - return []; - } - - if ( - isSentinelOneAlert && - sentinelOneManualHostActionsEnabled && - sentinelOneAgentId && - externalAgentStatus && - hasActionsAllPrivileges - ) { - return menuItems; - } - - if ( - isCrowdstrikeAlert && - crowdstrikeManualHostActionsEnabled && - crowdstrikeAgentId && - externalAgentStatus && - hasActionsAllPrivileges - ) { - return menuItems; - } - - if ( - isEndpointAlert && - doesHostSupportIsolation && - !loadingHostIsolationStatus && - (canIsolateHost || (isHostIsolated && !canUnIsolateHost)) - ) { - return menuItems; - } - - return []; - }, [ - canIsolateHost, - canUnIsolateHost, - doesHostSupportIsolation, - hasActionsAllPrivileges, - isEndpointAlert, - isHostIsolated, - isHostIsolationPanelOpen, - isSentinelOneAlert, - loadingHostIsolationStatus, - menuItems, - externalAgentStatus, - sentinelOneAgentId, - sentinelOneManualHostActionsEnabled, - crowdstrikeAgentId, - isCrowdstrikeAlert, - crowdstrikeManualHostActionsEnabled, - ]); -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx index 442b4b2d4ff62f..d8150057dd44b3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx @@ -22,26 +22,15 @@ import { useHttp, useKibana } from '../../../common/lib/kibana'; import { mockCasesContract } from '@kbn/cases-plugin/public/mocks'; import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '../../../common/components/user_privileges/user_privileges_context'; import { useUserPrivileges } from '../../../common/components/user_privileges'; -import { - HOST_ENDPOINT_UNENROLLED_TOOLTIP, - LOADING_ENDPOINT_DATA_TOOLTIP, - NOT_FROM_ENDPOINT_HOST_TOOLTIP, -} from '../endpoint_responder/translations'; -import { endpointMetadataHttpMocks } from '../../../management/pages/endpoint_hosts/mocks'; -import type { HttpSetup } from '@kbn/core/public'; -import { - isAlertFromEndpointAlert, - isAlertFromEndpointEvent, -} from '../../../common/utils/endpoint_alert_check'; import { getUserPrivilegesMockDefaultValue } from '../../../common/components/user_privileges/__mocks__'; import { allCasesPermissions } from '../../../cases_test_utils'; -import { HostStatus } from '../../../../common/endpoint/types'; -import { ENDPOINT_CAPABILITIES } from '../../../../common/endpoint/service/response_actions/constants'; import { ALERT_ASSIGNEES_CONTEXT_MENU_ITEM_TITLE, ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE, } from '../../../common/components/toolbar/bulk_actions/translations'; +jest.mock('../../../common/components/endpoint/host_isolation'); +jest.mock('../../../common/components/endpoint/responder'); jest.mock('../../../common/components/user_privileges'); jest.mock('../user_info', () => ({ @@ -66,34 +55,18 @@ jest.mock('../../../common/hooks/use_license', () => ({ useLicense: jest.fn().mockReturnValue({ isPlatinumPlus: () => true, isEnterprise: () => false }), })); -jest.mock('../../../common/utils/endpoint_alert_check', () => { - const realEndpointAlertCheckUtils = jest.requireActual( - '../../../common/utils/endpoint_alert_check' - ); - return { - isTimelineEventItemAnAlert: realEndpointAlertCheckUtils.isTimelineEventItemAnAlert, - isAlertFromEndpointAlert: jest.fn().mockReturnValue(true), - isAlertFromEndpointEvent: jest.fn().mockReturnValue(true), - }; -}); - -jest.mock('../../../../common/endpoint/service/host_isolation/utils', () => { - return { - isIsolationSupported: jest.fn().mockReturnValue(true), - }; -}); - -jest.mock('../../containers/detection_engine/alerts/use_host_isolation_status', () => { - return { - useEndpointHostIsolationStatus: jest.fn().mockReturnValue({ - loading: false, - isIsolated: false, - agentStatus: 'healthy', - }), - }; -}); - -jest.mock('../../../common/components/user_privileges'); +jest.mock( + '../../../common/components/endpoint/host_isolation/from_alerts/use_host_isolation_status', + () => { + return { + useEndpointHostIsolationStatus: jest.fn().mockReturnValue({ + loading: false, + isIsolated: false, + agentStatus: 'healthy', + }), + }; + } +); describe('take action dropdown', () => { let defaultProps: TakeActionDropdownProps; @@ -292,15 +265,15 @@ describe('take action dropdown', () => { } }; - const setAlertDetailsDataMockToEndpointAgent = () => { + const setAgentTypeOnAlertDetailsDataMock = (agentType: string = 'endpoint') => { if (defaultProps.detailsData) { defaultProps.detailsData = defaultProps.detailsData.map((obj) => { if (obj.field === 'agent.type') { return { category: 'agent', field: 'agent.type', - values: ['endpoint'], - originalValue: ['endpoint'], + values: [agentType], + originalValue: [agentType], }; } if (obj.field === 'agent.id') { @@ -335,9 +308,32 @@ describe('take action dropdown', () => { } }; - describe('should correctly enable/disable the "Add Endpoint event filter" button', () => { - let wrapper: ReactWrapper; + let wrapper: ReactWrapper; + const render = (): ReactWrapper => { + wrapper = mount( + + + + ); + wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click'); + + return wrapper; + }; + + it('should include the Isolate/Release action', () => { + render(); + + expect(wrapper.exists('[data-test-subj="isolate-host-action-item"]')).toBe(true); + }); + + it('should include the Responder action', () => { + render(); + + expect(wrapper.exists('[data-test-subj="endpointResponseActions-action-item"]')).toBe(true); + }); + + describe('should correctly enable/disable the "Add Endpoint event filter" button', () => { beforeEach(() => { setTypeOnEcsDataWithAgentType(); setAlertDetailsDataMockToEvent(); @@ -348,12 +344,7 @@ describe('take action dropdown', () => { ...mockInitialUserPrivilegesState(), endpointPrivileges: { loading: false, canWriteEventFilters: true }, }); - wrapper = mount( - - - - ); - wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click'); + render(); await waitFor(() => { expect( wrapper.find('[data-test-subj="add-event-filter-menu-item"]').last().getDOMNode() @@ -366,204 +357,18 @@ describe('take action dropdown', () => { ...mockInitialUserPrivilegesState(), endpointPrivileges: { loading: false, canWriteEventFilters: false }, }); - wrapper = mount( - - - - ); - wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click'); + render(); await waitFor(() => { expect(wrapper.exists('[data-test-subj="add-event-filter-menu-item"]')).toBeFalsy(); }); }); test('should hide the "Add Endpoint event filter" button if provided no event from endpoint', async () => { + setAgentTypeOnAlertDetailsDataMock('filebeat'); setTypeOnEcsDataWithAgentType('filebeat'); - - wrapper = mount( - - - - ); - wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click'); - await waitFor(() => { - expect(wrapper.exists('[data-test-subj="add-event-filter-menu-item"]')).toBeFalsy(); - }); - }); - }); - - describe('should correctly enable/disable the "Isolate Host" button', () => { - let wrapper: ReactWrapper; - - const render = (): ReactWrapper => { - wrapper = mount( - - - - ); - wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click'); - - return wrapper; - }; - - const isolateHostButtonExists = (): ReturnType => { - return wrapper.exists('[data-test-subj="isolate-host-action-item"]'); - }; - - beforeEach(() => { - setTypeOnEcsDataWithAgentType(); - }); - - it('should show Isolate host button if user has "Host isolation" privileges set to all', async () => { - (useUserPrivileges as jest.Mock).mockReturnValue({ - ...mockInitialUserPrivilegesState(), - endpointPrivileges: { loading: false, canIsolateHost: true }, - }); - render(); - - await waitFor(() => { - expect(isolateHostButtonExists()).toBeTruthy(); - }); - }); - it('should hide Isolate host button if user has "Host isolation" privileges set to none', () => { - (useUserPrivileges as jest.Mock).mockReturnValue({ - ...mockInitialUserPrivilegesState(), - endpointPrivileges: { loading: false, canIsolateHost: false }, - }); - render(); - - expect(isolateHostButtonExists()).toBeFalsy(); - }); - }); - - describe('should correctly enable/disable the "Respond" button', () => { - let wrapper: ReactWrapper; - let apiMocks: ReturnType; - - const render = (): ReactWrapper => { - wrapper = mount( - - - - ); - wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click'); - - return wrapper; - }; - - const findLaunchResponderButton = (): ReturnType => { - return wrapper.find('[data-test-subj="endpointResponseActions-action-item"]'); - }; - - beforeAll(() => { - // Un-Mock endpoint alert check hooks - const actualChecks = jest.requireActual('../../../common/utils/endpoint_alert_check'); - (isAlertFromEndpointEvent as jest.Mock).mockImplementation( - actualChecks.isAlertFromEndpointEvent - ); - (isAlertFromEndpointAlert as jest.Mock).mockImplementation( - actualChecks.isAlertFromEndpointAlert - ); - }); - - afterAll(() => { - // Set the mock modules back to what they were - (isAlertFromEndpointEvent as jest.Mock).mockImplementation(() => true); - (isAlertFromEndpointAlert as jest.Mock).mockImplementation(() => true); - }); - - beforeEach(() => { - setTypeOnEcsDataWithAgentType(); - apiMocks = endpointMetadataHttpMocks(mockStartServicesMock.http as jest.Mocked); - }); - - it('should not display the button if user is not allowed to write event filters', async () => { - (useUserPrivileges as jest.Mock).mockReturnValue({ - ...mockInitialUserPrivilegesState(), - endpointPrivileges: { loading: false, canWriteEventFilters: false }, - }); - render(); - - expect(findLaunchResponderButton()).toHaveLength(0); - }); - - it('should not display the button for Events', async () => { - setAlertDetailsDataMockToEvent(); - render(); - - expect(findLaunchResponderButton()).toHaveLength(0); - }); - - it('should enable button for non endpoint event type when defend integration present', async () => { - setTypeOnEcsDataWithAgentType('filebeat'); - if (defaultProps.detailsData) { - defaultProps.detailsData = generateAlertDetailsDataMock() as TimelineEventsDetailsItem[]; - } - render(); - - expect(findLaunchResponderButton().first().prop('disabled')).toBe(true); - expect(findLaunchResponderButton().first().prop('toolTipContent')).toEqual( - LOADING_ENDPOINT_DATA_TOOLTIP - ); - - await waitFor(() => { - expect(apiMocks.responseProvider.metadataDetails).toHaveBeenCalled(); - wrapper.update(); - - expect(findLaunchResponderButton().first().prop('disabled')).toBe(false); - expect(findLaunchResponderButton().first().prop('toolTipContent')).toEqual(undefined); - }); - }); - - it('should disable the button for non endpoint event type when defend integration not present', async () => { - setAlertDetailsDataMockToEndpointAgent(); - apiMocks.responseProvider.metadataDetails.mockImplementation(() => { - const error: Error & { body?: { statusCode: number } } = new Error(); - error.body = { statusCode: 404 }; - throw error; - }); render(); - await waitFor(() => { - expect(apiMocks.responseProvider.metadataDetails).toThrow(); - wrapper.update(); - - expect(findLaunchResponderButton().first().prop('disabled')).toBe(true); - expect(findLaunchResponderButton().first().prop('toolTipContent')).toEqual( - NOT_FROM_ENDPOINT_HOST_TOOLTIP - ); - }); - }); - - it('should disable the button if host status is unenrolled', async () => { - setAlertDetailsDataMockToEndpointAgent(); - const getApiResponse = apiMocks.responseProvider.metadataDetails.getMockImplementation(); - apiMocks.responseProvider.metadataDetails.mockImplementation(() => { - if (getApiResponse) { - return { - ...getApiResponse(), - metadata: { - ...getApiResponse().metadata, - Endpoint: { - ...getApiResponse().metadata.Endpoint, - capabilities: [...ENDPOINT_CAPABILITIES], - }, - }, - host_status: HostStatus.UNENROLLED, - }; - } - throw new Error('some error'); - }); - render(); - - await waitFor(() => { - expect(apiMocks.responseProvider.metadataDetails).toHaveBeenCalled(); - wrapper.update(); - - expect(findLaunchResponderButton().first().prop('disabled')).toBe(true); - expect(findLaunchResponderButton().first().prop('toolTipContent')).toEqual( - HOST_ENDPOINT_UNENROLLED_TOOLTIP - ); + expect(wrapper.exists('[data-test-subj="add-event-filter-menu-item"]')).toBeFalsy(); }); }); }); 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 2c769b81b0481b..1f4baaeae8df5f 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 @@ -11,23 +11,21 @@ import type { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-typ import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { TableId } from '@kbn/securitysolution-data-table'; import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { getAlertDetailsFieldValue } from '../../../common/lib/endpoint/utils/get_event_details_field_values'; import { GuidedOnboardingTourStep } from '../../../common/components/guided_onboarding_tour/tour_step'; import { AlertsCasesTourSteps, SecurityStepId, } from '../../../common/components/guided_onboarding_tour/tour_config'; import { isActiveTimeline } from '../../../helpers'; -import { useResponderActionItem } from '../endpoint_responder'; import { TAKE_ACTION } from '../alerts_table/additional_filters_action/translations'; import { useAlertExceptionActions } from '../alerts_table/timeline_actions/use_add_exception_actions'; import { useAlertsActions } from '../alerts_table/timeline_actions/use_alerts_actions'; import { useInvestigateInTimeline } from '../alerts_table/timeline_actions/use_investigate_in_timeline'; - import { useEventFilterAction } from '../alerts_table/timeline_actions/use_event_filter_action'; -import { useHostIsolationAction } from '../host_isolation/use_host_isolation_action'; -import { getFieldValue } from '../host_isolation/helpers'; +import { useResponderActionItem } from '../../../common/components/endpoint/responder'; +import { useHostIsolationAction } from '../../../common/components/endpoint/host_isolation'; import type { Status } from '../../../../common/api/detection_engine'; -import { isAlertFromEndpointAlert } from '../../../common/utils/endpoint_alert_check'; import { useUserPrivileges } from '../../../common/components/user_privileges'; import { useAddToCaseActions } from '../alerts_table/timeline_actions/use_add_to_case_actions'; import { useKibana } from '../../../common/lib/kibana'; @@ -97,7 +95,10 @@ export const TakeActionDropdown = React.memo( ].reduce( (acc, curr) => ({ ...acc, - [curr.name]: getFieldValue({ category: curr.category, field: curr.field }, detailsData), + [curr.name]: getAlertDetailsFieldValue( + { category: curr.category, field: curr.field }, + detailsData + ), }), {} as ActionsData ), @@ -107,11 +108,10 @@ export const TakeActionDropdown = React.memo( const isEvent = actionsData.eventKind === 'event'; const isAgentEndpoint = useMemo(() => ecsData?.agent?.type?.includes('endpoint'), [ecsData]); - const isEndpointEvent = useMemo(() => isEvent && isAgentEndpoint, [isEvent, isAgentEndpoint]); - const agentId = useMemo( - () => getFieldValue({ category: 'agent', field: 'agent.id' }, detailsData), + const osqueryAgentId = useMemo( + () => getAlertDetailsFieldValue({ category: 'agent', field: 'agent.id' }, detailsData), [detailsData] ); @@ -157,7 +157,7 @@ export const TakeActionDropdown = React.memo( ); const { exceptionActionItems } = useAlertExceptionActions({ - isEndpointAlert: isAlertFromEndpointAlert({ ecsData }), + isEndpointAlert: Boolean(isAgentEndpoint), onAddExceptionTypeClick: handleOnAddExceptionTypeClick, }); @@ -208,13 +208,13 @@ export const TakeActionDropdown = React.memo( }); const osqueryAvailable = osquery?.isOsqueryAvailable({ - agentId, + agentId: osqueryAgentId, }); const handleOnOsqueryClick = useCallback(() => { - onOsqueryClick(agentId); + onOsqueryClick(osqueryAgentId); setIsPopoverOpen(false); - }, [onOsqueryClick, setIsPopoverOpen, agentId]); + }, [onOsqueryClick, setIsPopoverOpen, osqueryAgentId]); const osqueryActionItem = useMemo( () => diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/api.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/api.ts index 815628f8a3d4ac..0b198793a31ff9 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/api.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/api.ts @@ -30,7 +30,7 @@ import type { CheckSignalIndex, UpdateAlertStatusByIdsProps, } from './types'; -import { isolateHost, unIsolateHost } from '../../../../common/lib/endpoint_isolation'; +import { isolateHost, unIsolateHost } from '../../../../common/lib/endpoint/endpoint_isolation'; import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables'; /** diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx index 2a6e51d5839a8a..f60866be1e3ead 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx @@ -77,7 +77,7 @@ import { useSourcererDataView } from '../../../../sourcerer/containers'; import { EmptyPrompt } from '../../../../common/components/empty_prompt'; import { AlertCountByRuleByStatus } from '../../../../common/components/alert_count_by_status'; import { useLicense } from '../../../../common/hooks/use_license'; -import { ResponderActionButton } from '../../../../detections/components/endpoint_responder/responder_action_button'; +import { ResponderActionButton } from '../../../../common/components/endpoint/responder'; import { useRefetchOverviewPageRiskScore } from '../../../../entity_analytics/api/hooks/use_refetch_overview_page_risk_score'; const ES_HOST_FIELD = 'host.name'; @@ -226,7 +226,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta rightSideItems={[ hostOverview.endpoint?.hostInfo?.metadata.elastic.agent.id && ( ), diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx index ae7707e971131f..6c4aafa0f7bd49 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx @@ -10,10 +10,12 @@ import React, { useCallback } from 'react'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { DocumentDetailsRightPanelKey } from '../shared/constants/panel_keys'; import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers'; -import { EndpointIsolateSuccess } from '../../../common/components/endpoint/host_isolation'; +import { + EndpointIsolateSuccess, + HostIsolationPanel, +} from '../../../common/components/endpoint/host_isolation'; import { useHostIsolationTools } from '../../../timelines/components/side_panel/event_details/use_host_isolation_tools'; import { useIsolateHostPanelContext } from './context'; -import { HostIsolationPanel } from '../../../detections/components/host_isolation'; import { FlyoutBody } from '../../shared/components/flyout_body'; /** diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.test.tsx index 5df180ed580759..63fd7651f04aa2 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.test.tsx @@ -6,128 +6,95 @@ */ import React from 'react'; -import { render } from '@testing-library/react'; -import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import type { IsolateHostPanelContext } from './context'; import { useIsolateHostPanelContext } from './context'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { PanelHeader } from './header'; -import { FLYOUT_HEADER_TITLE_TEST_ID } from './test_ids'; -import { isAlertFromSentinelOneEvent } from '../../../common/utils/sentinelone_alert_check'; -import { isAlertFromCrowdstrikeEvent } from '../../../common/utils/crowdstrike_alert_check'; +import type { AppContextTestRender } from '../../../common/mock/endpoint'; +import { createAppRootMockRenderer, endpointAlertDataMock } from '../../../common/mock/endpoint'; +import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; +import { RESPONSE_ACTION_AGENT_TYPE } from '../../../../common/endpoint/service/response_actions/constants'; +import { ISOLATE_HOST, UNISOLATE_HOST } from '../../../common/components/endpoint/host_isolation'; import { TECHNICAL_PREVIEW } from '../../../common/translations'; -jest.mock('../../../common/hooks/use_experimental_features'); -jest.mock('../../../common/utils/sentinelone_alert_check'); -jest.mock('../../../common/utils/crowdstrike_alert_check'); jest.mock('./context'); -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; -const mockIsAlertFromSentinelOneEvent = isAlertFromSentinelOneEvent as jest.Mock; -const mockIsAlertFromCrowdstrike = isAlertFromCrowdstrikeEvent as jest.Mock; +describe('Isolation Flyout PanelHeader', () => { + let render: () => ReturnType; -const renderPanelHeader = () => - render( - - - - ); + const setUseIsolateHostPanelContext = (data: Partial = {}) => { + const panelContextMock: IsolateHostPanelContext = { + eventId: 'some-even-1', + indexName: 'some-index-name', + scopeId: 'some-scope-id', + dataFormattedForFieldBrowser: endpointAlertDataMock.generateEndpointAlertDetailsItemData(), + isolateAction: 'isolateHost', + ...data, + }; + + (useIsolateHostPanelContext as jest.Mock).mockReturnValue(panelContextMock); + }; -describe('', () => { beforeEach(() => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); - mockIsAlertFromSentinelOneEvent.mockReturnValue(false); - mockIsAlertFromCrowdstrike.mockReturnValue(false); - }); + const appContextMock = createAppRootMockRenderer(); - it.each([ - { - isolateAction: 'isolateHost', - title: 'Isolate host', - }, - { - isolateAction: 'unisolateHost', - title: 'Release host', - }, - ])('should display release host message', ({ isolateAction, title }) => { - (useIsolateHostPanelContext as jest.Mock).mockReturnValue({ isolateAction }); + appContextMock.setExperimentalFlag({ + responseActionsSentinelOneV1Enabled: true, + responseActionsCrowdstrikeManualHostIsolationEnabled: true, + }); - const { getByTestId } = renderPanelHeader(); + render = () => appContextMock.render(); - expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent(title); + setUseIsolateHostPanelContext({ + isolateAction: 'isolateHost', + dataFormattedForFieldBrowser: endpointAlertDataMock.generateEndpointAlertDetailsItemData(), + }); }); - it.each([ - { - action: 'isolateHost', - alertCheck: mockIsAlertFromSentinelOneEvent, - description: 'SentinelOne', - }, - { - action: 'unisolateHost', - alertCheck: mockIsAlertFromSentinelOneEvent, - description: 'SentinelOne', - }, - { - action: 'isolateHost', - alertCheck: mockIsAlertFromCrowdstrike, - description: 'Crowdstrike', - }, - { - action: 'unisolateHost', - alertCheck: mockIsAlertFromCrowdstrike, - description: 'Crowdstrike', - }, - ])( - 'should display beta badge on $description alerts for %s host message', - ({ action, alertCheck }) => { - (useIsolateHostPanelContext as jest.Mock).mockReturnValue({ - isolateAction: action, - }); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); - alertCheck.mockReturnValue(true); + afterEach(() => { + jest.clearAllMocks(); + }); - const { getByTestId } = renderPanelHeader(); + const testConditions: Array<{ + action: IsolateHostPanelContext['isolateAction']; + agentType: ResponseActionAgentType; + title: string; + // if `expectedBadgeText` is `undefined`, then it validates that the badge is not displayed + expectedBadgeText: string | undefined; + }> = []; - expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent(TECHNICAL_PREVIEW); - } - ); + for (const agentType of RESPONSE_ACTION_AGENT_TYPE) { + (['isolateHost', 'unisolateHost'] as Array).forEach( + (action) => { + testConditions.push({ + action, + agentType, + title: action === 'isolateHost' ? ISOLATE_HOST : UNISOLATE_HOST, + expectedBadgeText: + agentType === 'crowdstrike' || agentType === 'sentinel_one' + ? TECHNICAL_PREVIEW + : undefined, + }); + } + ); + } - it.each([ - { - action: 'isolateHost', - alertCheck: mockIsAlertFromSentinelOneEvent, - description: 'SentinelOne', - }, - { - action: 'unisolateHost', - alertCheck: mockIsAlertFromSentinelOneEvent, - description: 'SentinelOne', - }, - { - action: 'isolateHost', - alertCheck: mockIsAlertFromCrowdstrike, - description: 'Crowdstrike', - }, - { - action: 'unisolateHost', - alertCheck: mockIsAlertFromCrowdstrike, - description: 'Crowdstrike', - }, - ])( - 'should not display beta badge on $description alerts for %s host message', - ({ action, alertCheck }) => { - (useIsolateHostPanelContext as jest.Mock).mockReturnValue({ + it.each(testConditions)( + 'should display correct flyout header title for $action on agentType $agentType', + ({ action, agentType, title, expectedBadgeText }) => { + setUseIsolateHostPanelContext({ isolateAction: action, + dataFormattedForFieldBrowser: + endpointAlertDataMock.generateAlertDetailsItemDataForAgentType(agentType), }); - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); - alertCheck.mockReturnValue(false); + const { getByTestId, queryByTestId } = render(); - const { getByTestId } = renderPanelHeader(); + expect(getByTestId('flyoutHostIsolationHeaderTitle')).toHaveTextContent(title); - expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).not.toHaveTextContent(TECHNICAL_PREVIEW); + if (expectedBadgeText) { + expect(getByTestId('flyoutHostIsolationHeaderBadge')).toHaveTextContent(expectedBadgeText); + } else { + expect(queryByTestId('flyoutHostIsolationHeaderBadge')).toBeNull(); + } } ); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.tsx index ead599d38e4987..635d273b432370 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.tsx @@ -7,51 +7,40 @@ import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import type { FC } from 'react'; -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { isAlertFromCrowdstrikeEvent } from '../../../common/utils/crowdstrike_alert_check'; +import React, { useMemo } from 'react'; +import { useAlertResponseActionsSupport } from '../../../common/hooks/endpoint/use_alert_response_actions_support'; import { TECHNICAL_PREVIEW, TECHNICAL_PREVIEW_TOOLTIP } from '../../../common/translations'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; -import { isAlertFromSentinelOneEvent } from '../../../common/utils/sentinelone_alert_check'; import { useIsolateHostPanelContext } from './context'; import { FLYOUT_HEADER_TITLE_TEST_ID } from './test_ids'; import { FlyoutHeader } from '../../shared/components/flyout_header'; +import { ISOLATE_HOST, UNISOLATE_HOST } from '../../../common/components/endpoint'; /** * Document details expandable right section header for the isolate host panel */ export const PanelHeader: FC = () => { const { isolateAction, dataFormattedForFieldBrowser: data } = useIsolateHostPanelContext(); - const isSentinelOneAlert = isAlertFromSentinelOneEvent({ data }); - const isSentinelOneV1Enabled = useIsExperimentalFeatureEnabled( - 'responseActionsSentinelOneV1Enabled' - ); + const { + isSupported: supportsResponseActions, + details: { agentType }, + } = useAlertResponseActionsSupport(data); + + const showTechPreviewBadge: boolean = useMemo(() => { + return supportsResponseActions && (agentType === 'sentinel_one' || agentType === 'crowdstrike'); + }, [agentType, supportsResponseActions]); - const isAlertFromCrowdstrikeAlert = isAlertFromCrowdstrikeEvent({ data }); - const responseActionsCrowdstrikeManualHostIsolationEnabled = useIsExperimentalFeatureEnabled( - 'responseActionsCrowdstrikeManualHostIsolationEnabled' - ); - const showAsTechPreview = - (isSentinelOneV1Enabled && isSentinelOneAlert) || - (responseActionsCrowdstrikeManualHostIsolationEnabled && isAlertFromCrowdstrikeAlert); const title = ( - - {isolateAction === 'isolateHost' ? ( - - ) : ( - - )} + + {isolateAction === 'isolateHost' ? <>{ISOLATE_HOST} : <>{UNISOLATE_HOST}} - {showAsTechPreview && ( + {showTechPreviewBadge && ( - + )} diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx index be495a6b16df6a..51e60b67ed8b00 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx @@ -11,12 +11,10 @@ import { EuiFlexItem, EuiLink } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { ResponseActionAgentType } from '../../../../../common/endpoint/service/response_actions/constants'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { SENTINEL_ONE_AGENT_ID_FIELD } from '../../../../common/utils/sentinelone_alert_check'; import { AgentStatus, EndpointAgentStatusById, -} from '../../../../common/components/agents/agent_status'; -import { CROWDSTRIKE_AGENT_ID_FIELD } from '../../../../common/utils/crowdstrike_alert_check'; +} from '../../../../common/components/endpoint/agents/agent_status'; import { useRightPanelContext } from '../context'; import { AGENT_STATUS_FIELD_NAME, @@ -32,6 +30,7 @@ import { HIGHLIGHTED_FIELDS_CELL_TEST_ID, HIGHLIGHTED_FIELDS_LINKED_CELL_TEST_ID, } from './test_ids'; +import { RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD } from '../../../../../common/endpoint/service/response_actions/constants'; interface LinkFieldCellProps { /** @@ -117,11 +116,11 @@ export const HighlightedFieldsCell: VFC = ({ originalField, }) => { const isSentinelOneAgentIdField = useMemo( - () => originalField === SENTINEL_ONE_AGENT_ID_FIELD, + () => originalField === RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one, [originalField] ); const isCrowdstrikeAgentIdField = useMemo( - () => originalField === CROWDSTRIKE_AGENT_ID_FIELD, + () => originalField === RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.crowdstrike, [originalField] ); const agentType: ResponseActionAgentType = useMemo(() => { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx index 3a18b49a0fc17c..c78e7313792c88 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx @@ -12,7 +12,9 @@ import { mockDataFormattedForFieldBrowserWithOverridenField, } from '../mocks/mock_data_formatted_for_field_browser'; import { useHighlightedFields } from './use_highlighted_fields'; -import { SENTINEL_ONE_AGENT_ID_FIELD } from '../../../../common/utils/sentinelone_alert_check'; +import { RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD } from '../../../../../common/endpoint/service/response_actions/constants'; + +jest.mock('../../../../common/experimental_features_service'); const dataFormattedForFieldBrowser = mockDataFormattedForFieldBrowser; @@ -104,7 +106,7 @@ describe('useHighlightedFields', () => { useHighlightedFields({ dataFormattedForFieldBrowser: dataFormattedForFieldBrowser.concat({ category: 'observer', - field: `observer.${SENTINEL_ONE_AGENT_ID_FIELD}`, + field: `observer.${RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one}`, values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], originalValue: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], isObjectArray: false, @@ -154,7 +156,7 @@ describe('useHighlightedFields', () => { }, { category: 'observer', - field: SENTINEL_ONE_AGENT_ID_FIELD, + field: RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one, values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], originalValue: ['deb35a20-70f8-458e-a64a-c9e6f7575893'], isObjectArray: false, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts index c60bb96c779740..571e01b9a2e224 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts @@ -8,15 +8,8 @@ import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import { find, isEmpty } from 'lodash/fp'; import { ALERT_RULE_TYPE } from '@kbn/rule-data-utils'; -import { - CROWDSTRIKE_AGENT_ID_FIELD, - isAlertFromCrowdstrikeEvent, -} from '../../../../common/utils/crowdstrike_alert_check'; -import { - SENTINEL_ONE_AGENT_ID_FIELD, - isAlertFromSentinelOneEvent, -} from '../../../../common/utils/sentinelone_alert_check'; -import { isAlertFromEndpointEvent } from '../../../../common/utils/endpoint_alert_check'; +import { useAlertResponseActionsSupport } from '../../../../common/hooks/endpoint/use_alert_response_actions_support'; +import { isResponseActionsAlertAgentIdField } from '../../../../common/lib/endpoint'; import { getEventCategoriesFromData, getEventFieldsToDisplay, @@ -53,6 +46,7 @@ export const useHighlightedFields = ({ dataFormattedForFieldBrowser, investigationFields, }: UseHighlightedFieldsParams): UseHighlightedFieldsResult => { + const responseActionsSupport = useAlertResponseActionsSupport(dataFormattedForFieldBrowser); const eventCategories = getEventCategoriesFromData(dataFormattedForFieldBrowser); const eventCodeField = find( @@ -99,26 +93,12 @@ export const useHighlightedFields = ({ field.id = field.legacyId; } - // if the field is agent.id and the event is not an endpoint event we skip it - if ( - field.id === 'agent.id' && - !isAlertFromEndpointEvent({ data: dataFormattedForFieldBrowser }) - ) { - return acc; - } - - // if the field is observer.serial_number and the event is not a sentinel one event we skip it - if ( - field.id === SENTINEL_ONE_AGENT_ID_FIELD && - !isAlertFromSentinelOneEvent({ data: dataFormattedForFieldBrowser }) - ) { - return acc; - } - - // if the field is crowdstrike.event.DeviceId and the event is not a crowdstrike event we skip it + // If the field is one used by a supported Response Actions agentType, + // but the alert field is not the one that the agentType on the alert host uses, + // then exit and return accumulator if ( - field.id === CROWDSTRIKE_AGENT_ID_FIELD && - !isAlertFromCrowdstrikeEvent({ data: dataFormattedForFieldBrowser }) + isResponseActionsAlertAgentIdField(field.id) && + responseActionsSupport.details.agentIdField !== field.id ) { return acc; } diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.tsx index 7334cf9d7e8f6e..1b8897c73271b0 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/fields/endpoint_policy_fields.tsx @@ -10,7 +10,7 @@ import { EuiHealth } from '@elastic/eui'; import type { EntityTableRows } from '../../shared/components/entity_table/types'; import type { ObservedEntityData } from '../../shared/components/observed_entity/types'; -import { EndpointAgentStatus } from '../../../../common/components/agents/agent_status'; +import { EndpointAgentStatus } from '../../../../common/components/endpoint/agents/agent_status'; import { getEmptyTagValue } from '../../../../common/components/empty_value'; import type { HostItem } from '../../../../../common/search_strategy'; import { HostPolicyResponseActionStatus } from '../../../../../common/search_strategy'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/status_action.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/status_action.tsx index 3f4b46b318b824..7ea0986a3e7213 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/status_action.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/status_action.tsx @@ -19,7 +19,7 @@ import type { CommandExecutionComponentProps } from '../../console/types'; import { FormattedError } from '../../formatted_error'; import { ConsoleCodeBlock } from '../../console/components/console_code_block'; import { POLICY_STATUS_TO_TEXT } from '../../../pages/endpoint_hosts/view/host_constants'; -import { getAgentStatusText } from '../../../../common/components/agents/agent_status_text'; +import { getAgentStatusText } from '../../../../common/components/endpoint/agents/agent_status_text'; export const EndpointStatusActionResult = memo< CommandExecutionComponentProps< diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/agent_info/agent_info.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/agent_info/agent_info.tsx index 4c0bf3ca511a29..7845b9d8b3efd4 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/agent_info/agent_info.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/agent_info/agent_info.tsx @@ -6,7 +6,7 @@ */ import React, { memo } from 'react'; -import { AgentStatus } from '../../../../../../common/components/agents/agent_status'; +import { AgentStatus } from '../../../../../../common/components/endpoint/agents/agent_status'; import { useAgentStatusHook } from '../../../../../hooks/agents/use_get_agent_status'; import type { ThirdPartyAgentInfo } from '../../../../../../../common/types'; import { HeaderAgentInfo } from '../header_agent_info'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/endpoint/header_endpoint_info.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/endpoint/header_endpoint_info.tsx index e9d73b3d62d63e..28ac70e7c969d6 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/endpoint/header_endpoint_info.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/endpoint/header_endpoint_info.tsx @@ -7,7 +7,7 @@ import React, { memo } from 'react'; import { EuiSkeletonText } from '@elastic/eui'; -import { EndpointAgentStatus } from '../../../../../../common/components/agents/agent_status'; +import { EndpointAgentStatus } from '../../../../../../common/components/endpoint/agents/agent_status'; import { HeaderAgentInfo } from '../header_agent_info'; import { useGetEndpointDetails } from '../../../../../hooks'; import type { Platform } from '../platforms'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/sentinel_one/header_sentinel_one_info.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/sentinel_one/header_sentinel_one_info.tsx index 212f66b6fe6e61..72a155833f9672 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/sentinel_one/header_sentinel_one_info.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/header_info/sentinel_one/header_sentinel_one_info.tsx @@ -6,7 +6,7 @@ */ import React, { memo } from 'react'; -import { AgentStatus } from '../../../../../../common/components/agents/agent_status'; +import { AgentStatus } from '../../../../../../common/components/endpoint/agents/agent_status'; import { useAgentStatusHook } from '../../../../../hooks/agents/use_get_agent_status'; import { useIsExperimentalFeatureEnabled } from '../../../../../../common/hooks/use_experimental_features'; import type { ThirdPartyAgentInfo } from '../../../../../../../common/types'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.tsx index d18a8526fb3eb9..727d30a6c75b48 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.tsx @@ -9,6 +9,7 @@ import React, { memo, useMemo } from 'react'; import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import { isAgentTypeAndActionSupported } from '../../../../common/lib/endpoint'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { useAgentStatusHook } from '../../../hooks/agents/use_get_agent_status'; import type { ResponseActionAgentType } from '../../../../../common/endpoint/service/response_actions/constants'; @@ -27,16 +28,10 @@ export const OfflineCallout = memo(({ agentType, endpointId const isCrowdstrikeAgent = agentType === 'crowdstrike'; const getAgentStatus = useAgentStatusHook(); const agentStatusClientEnabled = useIsExperimentalFeatureEnabled('agentStatusClientEnabled'); - const isSentinelOneV1Enabled = useIsExperimentalFeatureEnabled( - 'responseActionsSentinelOneV1Enabled' - ); - const sentinelOneManualHostActionsEnabled = useIsExperimentalFeatureEnabled( - 'sentinelOneManualHostActionsEnabled' - ); - const crowdstrikeManualHostActionsEnabled = useIsExperimentalFeatureEnabled( - 'responseActionsCrowdstrikeManualHostIsolationEnabled' - ); + const isAgentTypeEnabled = useMemo(() => { + return isAgentTypeAndActionSupported(agentType); + }, [agentType]); const { data: endpointDetails } = useGetEndpointDetails(endpointId, { refetchInterval: 10000, @@ -45,9 +40,7 @@ export const OfflineCallout = memo(({ agentType, endpointId const { data } = getAgentStatus([endpointId], agentType, { enabled: - (sentinelOneManualHostActionsEnabled && isSentinelOneAgent) || - (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAgent) || - (isEndpointAgent && agentStatusClientEnabled), + (isEndpointAgent && agentStatusClientEnabled) || (!isEndpointAgent && isAgentTypeEnabled), }); const showOfflineCallout = useMemo( () => @@ -64,11 +57,7 @@ export const OfflineCallout = memo(({ agentType, endpointId ] ); - if ( - (isEndpointAgent && !endpointDetails) || - (isSentinelOneV1Enabled && isSentinelOneAgent && !data) || - (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAgent && !data) - ) { + if ((isEndpointAgent && !endpointDetails) || (isAgentTypeEnabled && !data)) { return null; } diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts index 22459383fde8f6..84624c2ce595bf 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { isActionSupportedByAgentType } from '../../../../../common/endpoint/service/response_actions/is_response_action_supported'; +import { isAgentTypeAndActionSupported } from '../../../../common/lib/endpoint'; import { getRbacControl } from '../../../../../common/endpoint/service/response_actions/utils'; import { UploadActionResult } from '../command_render_components/upload_action'; import { ArgumentFileSelector } from '../../console_argument_selectors'; @@ -139,6 +139,7 @@ const COMMENT_ARG_ABOUT = i18n.translate( export interface GetEndpointConsoleCommandsOptions { endpointAgentId: string; agentType: ResponseActionAgentType; + /** Applicable only for Endpoint Agents */ endpointCapabilities: ImmutableArray; endpointPrivileges: EndpointPrivileges; } @@ -556,43 +557,30 @@ export const getEndpointConsoleCommands = ({ } }; +/** @private */ +const disableCommand = (command: CommandDefinition, agentType: ResponseActionAgentType) => { + command.helpDisabled = true; + command.helpHidden = true; + command.validate = () => + UPGRADE_AGENT_FOR_RESPONDER(agentType, command.name as ConsoleResponseActionCommands); +}; + /** @private */ const adjustCommandsForSentinelOne = ({ commandList, }: { commandList: CommandDefinition[]; }): CommandDefinition[] => { - const featureFlags = ExperimentalFeaturesService.get(); - const isHostIsolationEnabled = featureFlags.responseActionsSentinelOneV1Enabled; - const isGetFileFeatureEnabled = featureFlags.responseActionsSentinelOneGetFileEnabled; - - const disableCommand = (command: CommandDefinition) => { - command.helpDisabled = true; - command.helpHidden = true; - command.validate = () => - UPGRADE_AGENT_FOR_RESPONDER('sentinel_one', command.name as ConsoleResponseActionCommands); - }; - return commandList.map((command) => { - const agentSupportsResponseAction = - command.name === 'status' - ? false - : isActionSupportedByAgentType( - 'sentinel_one', - RESPONSE_CONSOLE_COMMAND_TO_API_COMMAND_MAP[ - command.name as ConsoleResponseActionCommands - ], - 'manual' - ); - - // If command is not supported by SentinelOne - disable it if ( - !agentSupportsResponseAction || - (command.name === 'get-file' && !isGetFileFeatureEnabled) || - (command.name === 'isolate' && !isHostIsolationEnabled) || - (command.name === 'release' && !isHostIsolationEnabled) + command.name === 'status' || + !isAgentTypeAndActionSupported( + 'sentinel_one', + RESPONSE_CONSOLE_COMMAND_TO_API_COMMAND_MAP[command.name as ConsoleResponseActionCommands], + 'manual' + ) ) { - disableCommand(command); + disableCommand(command, 'sentinel_one'); } return command; @@ -605,35 +593,16 @@ const adjustCommandsForCrowdstrike = ({ }: { commandList: CommandDefinition[]; }): CommandDefinition[] => { - const featureFlags = ExperimentalFeaturesService.get(); - const isHostIsolationEnabled = featureFlags.responseActionsCrowdstrikeManualHostIsolationEnabled; - - const disableCommand = (command: CommandDefinition) => { - command.helpDisabled = true; - command.helpHidden = true; - command.validate = () => - UPGRADE_AGENT_FOR_RESPONDER('crowdstrike', command.name as ConsoleResponseActionCommands); - }; - return commandList.map((command) => { - const agentSupportsResponseAction = - command.name === 'status' - ? false - : isActionSupportedByAgentType( - 'crowdstrike', - RESPONSE_CONSOLE_COMMAND_TO_API_COMMAND_MAP[ - command.name as ConsoleResponseActionCommands - ], - 'manual' - ); - - // If command is not supported by Crowdstrike - disable it if ( - !agentSupportsResponseAction || - (command.name === 'isolate' && !isHostIsolationEnabled) || - (command.name === 'release' && !isHostIsolationEnabled) + command.name === 'status' || + !isAgentTypeAndActionSupported( + 'crowdstrike', + RESPONSE_CONSOLE_COMMAND_TO_API_COMMAND_MAP[command.name as ConsoleResponseActionCommands], + 'manual' + ) ) { - disableCommand(command); + disableCommand(command, 'crowdstrike'); } return command; diff --git a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_endpoint_pending_actions_summary.ts b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_endpoint_pending_actions_summary.ts index cee29041b0354a..57f0150317f5d4 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_endpoint_pending_actions_summary.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_get_endpoint_pending_actions_summary.ts @@ -9,7 +9,7 @@ import type { QueryObserverResult, UseQueryOptions } from '@tanstack/react-query import { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; import type { PendingActionsResponse } from '../../../../common/endpoint/types'; -import { fetchPendingActionsByAgentId } from '../../../common/lib/endpoint_pending_actions'; +import { fetchPendingActionsByAgentId } from '../../../common/lib/endpoint/endpoint_pending_actions'; /** * Retrieves the pending actions against the given Endpoint `agent.id`'s diff --git a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_isolate_endpoint_request.ts b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_isolate_endpoint_request.ts index b0fb5029ab15d3..b4cb131f6ae9c0 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_isolate_endpoint_request.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_isolate_endpoint_request.ts @@ -8,7 +8,7 @@ import type { UseMutationOptions, UseMutationResult } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; -import { isolateHost } from '../../../common/lib/endpoint_isolation'; +import { isolateHost } from '../../../common/lib/endpoint/endpoint_isolation'; import type { HostIsolationRequestBody, ResponseActionApiResponse, diff --git a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_release_endpoint_request.ts b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_release_endpoint_request.ts index f6d45393ae8850..b9e140dc3ba9d7 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_release_endpoint_request.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_release_endpoint_request.ts @@ -12,7 +12,7 @@ import type { HostIsolationRequestBody, ResponseActionApiResponse, } from '../../../../common/endpoint/types'; -import { unIsolateHost } from '../../../common/lib/endpoint_isolation'; +import { unIsolateHost } from '../../../common/lib/endpoint/endpoint_isolation'; /** * Create host release requests 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 7030f13bdd0f92..c3cc8adc3b4fe9 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 @@ -23,8 +23,8 @@ import { HOST_METADATA_LIST_ROUTE, METADATA_TRANSFORMS_STATUS_ROUTE, } from '../../../../common/endpoint/constants'; -import type { PendingActionsHttpMockInterface } from '../../../common/lib/endpoint_pending_actions/mocks'; -import { pendingActionsHttpMock } from '../../../common/lib/endpoint_pending_actions/mocks'; +import type { PendingActionsHttpMockInterface } from '../../../common/lib/endpoint/endpoint_pending_actions/mocks'; +import { pendingActionsHttpMock } from '../../../common/lib/endpoint/endpoint_pending_actions/mocks'; import { TRANSFORM_STATES } from '../../../../common/constants'; import type { TransformStatsResponse } from './types'; import type { diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts index ca1b0dfb56fea0..763bc15dace430 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts @@ -39,7 +39,7 @@ import { hostIsolationHttpMocks, hostIsolationRequestBodyMock, hostIsolationResponseMock, -} from '../../../../common/lib/endpoint_isolation/mocks'; +} from '../../../../common/lib/endpoint/endpoint_isolation/mocks'; import { endpointPageHttpMock, failedTransformStateMock } from '../mocks'; import { HOST_METADATA_LIST_ROUTE } from '../../../../../common/endpoint/constants'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index f8ffb703fb72ef..215a789a8b4ed1 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -29,8 +29,8 @@ import type { MetadataListResponse, ResponseActionApiResponse, } from '../../../../../common/endpoint/types'; -import { isolateHost, unIsolateHost } from '../../../../common/lib/endpoint_isolation'; -import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions'; +import { isolateHost, unIsolateHost } from '../../../../common/lib/endpoint/endpoint_isolation'; +import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint/endpoint_pending_actions'; import type { ImmutableMiddlewareAPI, ImmutableMiddlewareFactory } from '../../../../common/store'; import type { AppAction } from '../../../../common/store/actions'; import { sendGetEndpointSpecificPackagePolicies } from '../../../services/policies/policies'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts index 1bc156d0c5a377..a851d2273907d2 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts @@ -29,7 +29,7 @@ import { INGEST_API_PACKAGE_POLICIES, } from '../../../services/policies/ingest'; import type { GetPolicyListResponse } from '../../policy/types'; -import { pendingActionsResponseMock } from '../../../../common/lib/endpoint_pending_actions/mocks'; +import { pendingActionsResponseMock } from '../../../../common/lib/endpoint/endpoint_pending_actions/mocks'; import { ACTION_STATUS_ROUTE, ENDPOINT_DEFAULT_SORT_DIRECTION, diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx index 60ccec200d3c8a..0140cba0780edd 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx @@ -21,7 +21,7 @@ import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use import { AgentStatus, EndpointAgentStatus, -} from '../../../../../common/components/agents/agent_status'; +} from '../../../../../common/components/endpoint/agents/agent_status'; import { isPolicyOutOfDate } from '../../utils'; import type { HostInfo } from '../../../../../../common/endpoint/types'; import { useEndpointSelector } from '../hooks'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx index 75aeaf45a9a8a9..abda617e2a7798 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx @@ -20,7 +20,6 @@ import { agentPolicies, uiQueryParams } from '../../store/selectors'; import { useAppUrl } from '../../../../../common/lib/kibana/hooks'; import type { ContextMenuItemNavByRouterProps } from '../../../../components/context_menu_with_router_support/context_menu_item_nav_by_router'; import { isEndpointHostIsolated } from '../../../../../common/utils/validators'; -import { isIsolationSupported } from '../../../../../../common/endpoint/service/host_isolation/utils'; interface Options { isEndpointList: boolean; @@ -59,11 +58,6 @@ export const useEndpointActionItems = ( const endpointPolicyId = endpointMetadata.Endpoint.policy.applied.id; const endpointHostName = endpointMetadata.host.hostname; const fleetAgentId = endpointMetadata.elastic.agent.id; - const isolationSupported = isIsolationSupported({ - osName: endpointMetadata.host.os.name, - version: endpointMetadata.agent.version, - capabilities: endpointMetadata.Endpoint.capabilities, - }); const { show, selected_endpoint: _selectedEndpoint, ...currentUrlParams } = allCurrentUrlParams; const endpointActionsPath = getEndpointDetailsPath({ name: 'endpointActivityLog', @@ -101,7 +95,7 @@ export const useEndpointActionItems = ( /> ), }); - } else if (isolationSupported && canIsolateHost) { + } else if (canIsolateHost) { // For Platinum++ licenses, users also have ability to isolate isolationActions.push({ 'data-test-subj': 'isolateLink', diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx index 06029b8a646685..ceb9f1ce10e86e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx @@ -25,7 +25,7 @@ import { POLICY_STATUS_TO_HEALTH_COLOR, POLICY_STATUS_TO_TEXT } from './host_con import { mockPolicyResultList } from '../../policy/store/test_mock_utils'; import { getEndpointDetailsPath } from '../../../common/routing'; import { KibanaServices, useKibana, useToasts, useUiSetting$ } from '../../../../common/lib/kibana'; -import { hostIsolationHttpMocks } from '../../../../common/lib/endpoint_isolation/mocks'; +import { hostIsolationHttpMocks } from '../../../../common/lib/endpoint/endpoint_isolation/mocks'; import { isFailedResourceState, isLoadedResourceState, diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx index 440ad6a7560a6b..89473ece661a38 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx @@ -39,7 +39,7 @@ import { EndpointListNavLink } from './components/endpoint_list_nav_link'; import { AgentStatus, EndpointAgentStatus, -} from '../../../../common/components/agents/agent_status'; +} from '../../../../common/components/endpoint/agents/agent_status'; import { EndpointDetailsFlyout } from './details'; import * as selectors from '../store/selectors'; import { getEndpointPendingActionsCallback } from '../store/selectors'; diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx index ea6639ac8bcbfd..99eb2ed17e6b65 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx @@ -13,7 +13,7 @@ import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_ex import { AgentStatus, EndpointAgentStatus, -} from '../../../../common/components/agents/agent_status'; +} from '../../../../common/components/endpoint/agents/agent_status'; import { OverviewDescriptionList } from '../../../../common/components/overview_description_list'; import type { DescriptionList } from '../../../../../common/utility_types'; import { getEmptyTagValue } from '../../../../common/components/empty_value'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/back_to_alert_details_link.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/back_to_alert_details_link.tsx index 6ae4207a46f782..d14622cc0e7d0a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/back_to_alert_details_link.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/back_to_alert_details_link.tsx @@ -18,7 +18,7 @@ import React from 'react'; import { ISOLATE_HOST, UNISOLATE_HOST, -} from '../../../../../detections/components/host_isolation/translations'; +} from '../../../../../common/components/endpoint/host_isolation'; import { ALERT_DETAILS, TECHNICAL_PREVIEW, TECHNICAL_PREVIEW_DESCRIPTION } from '../translations'; const BackToAlertDetailsLinkComponent = ({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/body.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/body.tsx index 446aa27f5a3a55..5aea7657f8d61f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/body.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/body.tsx @@ -9,8 +9,10 @@ import { EuiFlyoutBody } from '@elastic/eui'; import styled from 'styled-components'; import React from 'react'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; -import { EndpointIsolateSuccess } from '../../../../../common/components/endpoint/host_isolation'; -import { HostIsolationPanel } from '../../../../../detections/components/host_isolation'; +import { + HostIsolationPanel, + EndpointIsolateSuccess, +} from '../../../../../common/components/endpoint/host_isolation'; import type { BrowserFields, TimelineEventsDetailsItem, diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.test.tsx index e48dbe5215f39f..a269dd422ca38e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.test.tsx @@ -37,14 +37,11 @@ const mockAlertDetailsDataWithIsObject = mockAlertDetailsData.map((detail) => { }; }) as TimelineEventsDetailsItem[]; -jest.mock('../../../../../../common/endpoint/service/host_isolation/utils', () => { - return { - isIsolationSupported: jest.fn().mockReturnValue(true), - }; -}); +jest.mock('../../../../../common/components/endpoint/host_isolation'); +jest.mock('../../../../../common/components/endpoint/responder'); jest.mock( - '../../../../../detections/containers/detection_engine/alerts/use_host_isolation_status', + '../../../../../common/components/endpoint/host_isolation/from_alerts/use_host_isolation_status', () => { return { useEndpointHostIsolationStatus: jest.fn().mockReturnValue({ @@ -74,16 +71,6 @@ jest.mock( ); jest.mock('../../../../../cases/components/use_insert_timeline'); -jest.mock('../../../../../common/utils/endpoint_alert_check', () => { - const realEndpointAlertCheckUtils = jest.requireActual( - '../../../../../common/utils/endpoint_alert_check' - ); - return { - isTimelineEventItemAnAlert: realEndpointAlertCheckUtils.isTimelineEventItemAnAlert, - isAlertFromEndpointAlert: jest.fn().mockReturnValue(true), - isAlertFromEndpointEvent: jest.fn().mockReturnValue(true), - }; -}); jest.mock( '../../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx index ea0df8fd3c684f..61dde196c6eda4 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/footer.tsx @@ -9,6 +9,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import { EuiFlyoutFooter, EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; import { find } from 'lodash/fp'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { getAlertDetailsFieldValue } from '../../../../../common/lib/endpoint/utils/get_event_details_field_values'; import { isActiveTimeline } from '../../../../../helpers'; import { TakeActionDropdown } from '../../../../../detections/components/take_action_dropdown'; import type { TimelineEventsDetailsItem } from '../../../../../../common/search_strategy'; @@ -16,7 +17,6 @@ import { useExceptionFlyout } from '../../../../../detections/components/alerts_ import { AddExceptionFlyoutWrapper } from '../../../../../detections/components/alerts_table/timeline_actions/alert_context_menu'; import { EventFiltersFlyout } from '../../../../../management/pages/event_filters/view/components/event_filters_flyout'; import { useEventFilterModal } from '../../../../../detections/components/alerts_table/timeline_actions/use_event_filter_modal'; -import { getFieldValue } from '../../../../../detections/components/host_isolation/helpers'; import type { Status } from '../../../../../../common/api/detection_engine'; import { OsqueryFlyout } from '../../../../../detections/components/osquery/osquery_flyout'; import { useRefetchByScope } from './use_refetch_by_scope'; @@ -93,7 +93,10 @@ export const FlyoutFooterComponent = ({ ].reduce( (acc, curr) => ({ ...acc, - [curr.name]: getFieldValue({ category: curr.category, field: curr.field }, detailsData), + [curr.name]: getAlertDetailsFieldValue( + { category: curr.category, field: curr.field }, + detailsData + ), }), {} as AddExceptionModalWrapperData ), diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/header.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/header.tsx index 0d139449b1ca2c..206d35e187cf6a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/header.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/flyout/header.tsx @@ -8,10 +8,10 @@ import { EuiFlyoutHeader } from '@elastic/eui'; import React, { useMemo } from 'react'; -import { SENTINEL_ONE_AGENT_ID_FIELD } from '../../../../../common/utils/sentinelone_alert_check'; import type { GetFieldsData } from '../../../../../common/hooks/use_get_fields_data'; import { ExpandableEventTitle } from '../expandable_event'; import { BackToAlertDetailsLink } from './back_to_alert_details_link'; +import { RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD } from '../../../../../../common/endpoint/service/response_actions/constants'; interface FlyoutHeaderComponentProps { eventId: string; @@ -45,7 +45,7 @@ const FlyoutHeaderContentComponent = ({ getFieldsData, }: FlyoutHeaderComponentProps) => { const isSentinelOneAlert = useMemo( - () => !!(isAlert && getFieldsData(SENTINEL_ONE_AGENT_ID_FIELD)?.length), + () => !!(isAlert && getFieldsData(RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one)?.length), [getFieldsData, isAlert] ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/helpers.tsx index 31491730adc838..acfdde85b68265 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/helpers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/helpers.tsx @@ -7,8 +7,8 @@ import { some } from 'lodash/fp'; import { useMemo } from 'react'; +import { getAlertDetailsFieldValue } from '../../../../common/lib/endpoint/utils/get_event_details_field_values'; import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy'; -import { getFieldValue } from '../../../../detections/components/host_isolation/helpers'; import { DEFAULT_ALERTS_INDEX, DEFAULT_PREVIEW_INDEX } from '../../../../../common/constants'; export interface GetBasicDataFromDetailsData { @@ -34,50 +34,57 @@ export const useBasicDataFromDetailsData = ( const ruleId = useMemo( () => isAlert - ? getFieldValue({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, data) - : getFieldValue({ category: 'signal', field: 'signal.rule.id' }, data), + ? getAlertDetailsFieldValue({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, data) + : getAlertDetailsFieldValue({ category: 'signal', field: 'signal.rule.id' }, data), [isAlert, data] ); const ruleName = useMemo( - () => getFieldValue({ category: 'kibana', field: 'kibana.alert.rule.name' }, data), + () => getAlertDetailsFieldValue({ category: 'kibana', field: 'kibana.alert.rule.name' }, data), [data] ); const ruleDescription = useMemo( - () => getFieldValue({ category: 'kibana', field: 'kibana.alert.rule.description' }, data), + () => + getAlertDetailsFieldValue( + { category: 'kibana', field: 'kibana.alert.rule.description' }, + data + ), [data] ); - const alertId = useMemo(() => getFieldValue({ category: '_id', field: '_id' }, data), [data]); + const alertId = useMemo( + () => getAlertDetailsFieldValue({ category: '_id', field: '_id' }, data), + [data] + ); const indexName = useMemo( - () => getFieldValue({ category: '_index', field: '_index' }, data), + () => getAlertDetailsFieldValue({ category: '_index', field: '_index' }, data), [data] ); const alertUrl = useMemo( - () => getFieldValue({ category: 'kibana', field: 'kibana.alert.url' }, data), + () => getAlertDetailsFieldValue({ category: 'kibana', field: 'kibana.alert.url' }, data), [data] ); const agentId = useMemo( - () => getFieldValue({ category: 'agent', field: 'agent.id' }, data), + () => getAlertDetailsFieldValue({ category: 'agent', field: 'agent.id' }, data), [data] ); const hostName = useMemo( - () => getFieldValue({ category: 'host', field: 'host.name' }, data), + () => getAlertDetailsFieldValue({ category: 'host', field: 'host.name' }, data), [data] ); const userName = useMemo( - () => getFieldValue({ category: 'user', field: 'user.name' }, data), + () => getAlertDetailsFieldValue({ category: 'user', field: 'user.name' }, data), [data] ); const timestamp = useMemo( - () => getFieldValue({ category: 'base', field: '@timestamp' }, data), + () => getAlertDetailsFieldValue({ category: 'base', field: '@timestamp' }, data), [data] ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.test.tsx index 0f186fdcf39d9c..edf2da964b2b36 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.test.tsx @@ -46,18 +46,12 @@ jest.mock('react-router-dom', () => { }; }); -jest.mock('../../../../../common/endpoint/service/host_isolation/utils', () => { - return { - isIsolationSupported: jest.fn().mockReturnValue(true), - }; -}); - jest.mock('../../../../common/hooks/use_space_id', () => ({ useSpaceId: jest.fn().mockReturnValue('testSpace'), })); jest.mock( - '../../../../detections/containers/detection_engine/alerts/use_host_isolation_status', + '../../../../common/components/endpoint/host_isolation/from_alerts/use_host_isolation_status', () => { return { useEndpointHostIsolationStatus: jest.fn().mockReturnValue({ @@ -97,12 +91,6 @@ jest.mock( ); jest.mock('../../../../cases/components/use_insert_timeline'); -jest.mock('../../../../common/utils/endpoint_alert_check', () => { - return { - isAlertFromEndpointAlert: jest.fn().mockReturnValue(true), - isAlertFromEndpointEvent: jest.fn().mockReturnValue(true), - }; -}); jest.mock( '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx index 49945e07796fa7..0982d829e8886f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx @@ -25,8 +25,10 @@ import { useHostIsolationTools } from './use_host_isolation_tools'; import { FlyoutBody, FlyoutHeader, FlyoutFooter } from './flyout'; import { useBasicDataFromDetailsData, getAlertIndexAlias } from './helpers'; import { useSpaceId } from '../../../../common/hooks/use_space_id'; -import { EndpointIsolateSuccess } from '../../../../common/components/endpoint/host_isolation'; -import { HostIsolationPanel } from '../../../../detections/components/host_isolation'; +import { + EndpointIsolateSuccess, + HostIsolationPanel, +} from '../../../../common/components/endpoint/host_isolation'; import { ALERT_SUMMARY_CONVERSATION_ID, ALERT_SUMMARY_CONTEXT_DESCRIPTION, diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/use_host_isolation_tools.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/use_host_isolation_tools.tsx index 5667c4e0a6156a..7885e1cd542dc6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/use_host_isolation_tools.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/use_host_isolation_tools.tsx @@ -7,7 +7,7 @@ import { useCallback, useMemo, useReducer } from 'react'; -import { useWithCaseDetailsRefresh } from '../../../../common/components/endpoint/host_isolation/endpoint_host_isolation_cases_context'; +import { useWithCaseDetailsRefresh } from '../../../../common/components/endpoint/host_isolation/from_cases/endpoint_host_isolation_cases_context'; interface HostIsolationStateReducer { isolateAction: 'isolateHost' | 'unisolateHost'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx index 46a3301d525691..28b60305b3f230 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx @@ -19,11 +19,10 @@ import { ALERT_HOST_CRITICALITY, ALERT_USER_CRITICALITY, } from '../../../../../../common/field_maps/field_names'; -import { SENTINEL_ONE_AGENT_ID_FIELD } from '../../../../../common/utils/sentinelone_alert_check'; import { AgentStatus, EndpointAgentStatusById, -} from '../../../../../common/components/agents/agent_status'; +} from '../../../../../common/components/endpoint/agents/agent_status'; import { INDICATOR_REFERENCE } from '../../../../../../common/cti/constants'; import { DefaultDraggable } from '../../../../../common/components/draggables'; import { Bytes, BYTES_FORMAT } from './bytes'; @@ -54,6 +53,7 @@ import { RuleStatus } from './rule_status'; import { HostName } from './host_name'; import { UserName } from './user_name'; import { AssetCriticalityLevel } from './asset_criticality_level'; +import { RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD } from '../../../../../../common/endpoint/service/response_actions/constants'; // simple black-list to prevent dragging and dropping fields such as message name const columnNamesNotDraggable = [MESSAGE_FIELD_NAME]; @@ -276,7 +276,7 @@ const FormattedFieldValueComponent: React.FC<{ ); } else if ( fieldName === AGENT_STATUS_FIELD_NAME && - fieldFromBrowserField?.name === SENTINEL_ONE_AGENT_ID_FIELD + fieldFromBrowserField?.name === RESPONSE_ACTIONS_ALERT_AGENT_ID_FIELD.sentinel_one ) { return ; } else if (fieldName === ALERT_HOST_CRITICALITY || fieldName === ALERT_USER_CRITICALITY) { diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 673bfbcfe49ff4..7305a2ca70a1d6 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -36143,8 +36143,6 @@ "xpack.securitySolution.flyout.entityDetails.userDetails.tableTabLabel": "Tableau", "xpack.securitySolution.flyout.entityDetails.userDetails.tabsLegend": "Onglets des documents de ressources", "xpack.securitySolution.flyout.entityDetails.valuesColumnTitle": "Valeurs", - "xpack.securitySolution.flyout.isolateHost.isolateTitle": "Isoler l'hôte", - "xpack.securitySolution.flyout.isolateHost.releaseTitle": "Libérer l'hôte", "xpack.securitySolution.flyout.left.insights.buttonGroupLegendLabel": "Options des informations exploitables", "xpack.securitySolution.flyout.left.insights.correlations.ancestryAlertsNoDataDescription": "Aucune alerte associée par ancêtre.", "xpack.securitySolution.flyout.left.insights.correlations.nameColumnLabel": "Nom", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 56df15a9c73bd2..2c6f6ea67b15e4 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -36118,8 +36118,6 @@ "xpack.securitySolution.flyout.entityDetails.userDetails.tableTabLabel": "表", "xpack.securitySolution.flyout.entityDetails.userDetails.tabsLegend": "アセットドキュメントタブ", "xpack.securitySolution.flyout.entityDetails.valuesColumnTitle": "値", - "xpack.securitySolution.flyout.isolateHost.isolateTitle": "ホストの分離", - "xpack.securitySolution.flyout.isolateHost.releaseTitle": "ホストのリリース", "xpack.securitySolution.flyout.left.insights.buttonGroupLegendLabel": "インサイトオプション", "xpack.securitySolution.flyout.left.insights.correlations.ancestryAlertsNoDataDescription": "上位項目に関連するアラートはありません。", "xpack.securitySolution.flyout.left.insights.correlations.nameColumnLabel": "名前", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 48d126c33a1e96..66f2bb582b4beb 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -36161,8 +36161,6 @@ "xpack.securitySolution.flyout.entityDetails.userDetails.tableTabLabel": "表", "xpack.securitySolution.flyout.entityDetails.userDetails.tabsLegend": "资产文档选项卡", "xpack.securitySolution.flyout.entityDetails.valuesColumnTitle": "值", - "xpack.securitySolution.flyout.isolateHost.isolateTitle": "隔离主机", - "xpack.securitySolution.flyout.isolateHost.releaseTitle": "释放主机", "xpack.securitySolution.flyout.left.insights.buttonGroupLegendLabel": "洞见选项", "xpack.securitySolution.flyout.left.insights.correlations.ancestryAlertsNoDataDescription": "无告警与体系相关。", "xpack.securitySolution.flyout.left.insights.correlations.nameColumnLabel": "名称", diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts index c7b54e26db890f..2d0d80af9c2426 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel.cy.ts @@ -41,6 +41,7 @@ import { DOCUMENT_DETAILS_FLYOUT_JSON_TAB, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB, DOCUMENT_DETAILS_FLYOUT_TABLE_TAB, + DOCUMENT_DETAILS_FLYOUT_FOOTER_ISOLATE_HOST, } from '../../../../screens/expandable_flyout/alert_details_right_panel'; import { closeFlyout, @@ -200,10 +201,10 @@ describe('Alert details expandable flyout right panel', { tags: ['@ess', '@serve // cy.log('should isolate host'); - // TODO figure out why isolate host isn't showing up in the dropdown + // TODO this will change when respond is improved // https://github.com/elastic/security-team/issues/6302 - // openTakeActionButton(); - // cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ISOLATE_HOST).should('be.visible'); + openTakeActionButton(); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_ISOLATE_HOST).should('be.disabled'); cy.log('should respond'); @@ -214,6 +215,7 @@ describe('Alert details expandable flyout right panel', { tags: ['@ess', '@serve cy.log('should investigate in timeline'); + openTakeActionButton(); selectTakeActionItem(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE); cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_INVESTIGATE_IN_TIMELINE_SECTION) .first() From ab21d4fee4f5e9149b85b1a0ce7fc0dbcfaa5062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Tue, 18 Jun 2024 14:23:16 +0200 Subject: [PATCH 024/123] [EBT] Combine packages (#186048) Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 6 +- package.json | 6 +- packages/analytics/README.md | 11 - packages/analytics/ebt/README.md | 11 + packages/analytics/{ => ebt}/client/README.md | 6 +- packages/analytics/{ => ebt}/client/index.ts | 1 + .../analytics_client/analytics_client.test.ts | 788 +++++++++--------- .../src/analytics_client/analytics_client.ts | 0 .../analytics_client/context_service.test.ts | 0 .../src/analytics_client/context_service.ts | 0 .../client/src/analytics_client/index.ts | 0 .../client/src/analytics_client/mocks.ts | 0 .../analytics_client/opt_in_config.test.ts | 0 .../src/analytics_client/opt_in_config.ts | 0 .../shippers_registry.test.ts | 0 .../src/analytics_client/shippers_registry.ts | 0 .../client/src/analytics_client/types.ts | 0 .../{ => ebt}/client/src/events/index.ts | 0 .../{ => ebt}/client/src/events/types.ts | 0 .../analytics/{ => ebt}/client/src/mocks.ts | 0 .../{ => ebt}/client/src/schema/index.ts | 0 .../{ => ebt}/client/src/schema/types.test.ts | 0 .../{ => ebt}/client/src/schema/types.ts | 0 .../src/schema/validation/excess.test.ts | 0 .../client/src/schema/validation/excess.ts | 0 .../client/src/schema/validation/index.ts | 0 .../schema/validation/schema_to_io_ts.test.ts | 0 .../src/schema/validation/schema_to_io_ts.ts | 0 .../schema/validation/validate_schema.test.ts | 0 .../src/schema/validation/validate_schema.ts | 0 .../{ => ebt}/client/src/shippers/index.ts | 0 .../{ => ebt}/client/src/shippers/mocks.ts | 0 .../{ => ebt}/client/src/shippers/types.ts | 0 packages/analytics/ebt/index.ts | 57 ++ .../analytics/{client => ebt}/jest.config.js | 6 +- .../analytics/{client => ebt}/kibana.jsonc | 2 +- .../analytics/{client => ebt}/package.json | 3 +- .../analytics/{ => ebt}/shippers/README.md | 2 +- .../shippers/elastic_v3/browser/README.md | 8 +- .../shippers/elastic_v3/browser/index.ts | 2 +- .../browser/src/browser_shipper.test.ts | 284 +++---- .../elastic_v3/browser/src/browser_shipper.ts | 11 +- .../shippers/elastic_v3/common/README.md | 4 +- .../shippers/elastic_v3/common/index.ts | 0 .../common/src/build_headers.test.ts | 0 .../elastic_v3/common/src/build_headers.ts | 0 .../elastic_v3/common/src/build_url.test.ts | 0 .../elastic_v3/common/src/build_url.ts | 0 .../common/src/error_with_code.test.ts | 0 .../elastic_v3/common/src/error_with_code.ts | 0 .../common/src/events_to_ndjson.test.ts | 2 +- .../elastic_v3/common/src/events_to_ndjson.ts | 2 +- .../src/report_telemetry_counters.test.ts | 2 +- .../common/src/report_telemetry_counters.ts | 2 +- .../shippers/elastic_v3/common/src/types.ts | 0 .../shippers/elastic_v3/server/README.md | 8 +- .../shippers/elastic_v3/server/index.ts | 2 +- .../server/src/server_shipper.test.mocks.ts | 0 .../server/src/server_shipper.test.ts | 571 +++++++++++++ .../elastic_v3/server/src/server_shipper.ts | 16 +- .../{ => ebt}/shippers/fullstory/README.md | 6 +- .../{ => ebt}/shippers/fullstory/index.ts | 0 .../fullstory/src/format_payload.test.ts | 0 .../shippers/fullstory/src/format_payload.ts | 0 .../src/fullstory_shipper.test.mocks.ts | 0 .../fullstory/src/fullstory_shipper.test.ts | 0 .../fullstory/src/fullstory_shipper.ts | 11 +- .../fullstory/src/get_parsed_version.test.ts | 0 .../fullstory/src/get_parsed_version.ts | 0 .../fullstory/src/load_snippet.test.ts | 24 +- .../shippers/fullstory/src/load_snippet.ts | 0 .../{ => ebt}/shippers/fullstory/src/types.ts | 0 .../analytics/{client => ebt}/tsconfig.json | 15 +- .../elastic_v3/browser/jest.config.js | 13 - .../shippers/elastic_v3/browser/kibana.jsonc | 5 - .../shippers/elastic_v3/browser/package.json | 7 - .../shippers/elastic_v3/browser/tsconfig.json | 21 - .../shippers/elastic_v3/common/jest.config.js | 13 - .../shippers/elastic_v3/common/kibana.jsonc | 5 - .../shippers/elastic_v3/common/package.json | 7 - .../shippers/elastic_v3/common/tsconfig.json | 19 - .../shippers/elastic_v3/server/jest.config.js | 13 - .../shippers/elastic_v3/server/kibana.jsonc | 5 - .../shippers/elastic_v3/server/package.json | 7 - .../server/src/server_shipper.test.ts | 624 -------------- .../shippers/elastic_v3/server/tsconfig.json | 21 - .../shippers/fullstory/jest.config.js | 13 - .../analytics/shippers/fullstory/kibana.jsonc | 5 - .../analytics/shippers/fullstory/package.json | 7 - .../shippers/fullstory/tsconfig.json | 21 - .../src/analytics_service.test.mocks.ts | 4 +- .../src/analytics_service.ts | 4 +- .../src/track_clicks.ts | 2 +- .../src/track_performance_measure_entries.ts | 2 +- .../src/track_viewport_size.ts | 2 +- .../tsconfig.json | 2 +- .../analytics/core-analytics-browser/index.ts | 38 + .../core-analytics-browser/src/types.ts | 2 +- .../core-analytics-browser/tsconfig.json | 2 +- .../src/analytics_service.test.mocks.ts | 4 +- .../src/analytics_service.ts | 4 +- .../tsconfig.json | 2 +- .../analytics/core-analytics-server/index.ts | 38 + .../core-analytics-server/src/contracts.ts | 2 +- .../core-analytics-server/tsconfig.json | 2 +- .../src/toasts/telemetry/event_types.ts | 2 +- .../tsconfig.json | 2 +- .../src/status_service.ts | 2 +- .../core-status-server-internal/tsconfig.json | 2 +- .../performance_metric_events/helpers.test.ts | 2 +- .../src/performance_metric_events/helpers.ts | 2 +- .../src/performance_metric_events/schema.ts | 2 +- packages/kbn-ebt-tools/tsconfig.json | 5 +- src/core/public/index.ts | 40 +- src/core/server/index.ts | 42 +- src/core/tsconfig.json | 1 - .../register_ebt_counters.test.ts | 2 +- .../register_ebt_counters.test.ts | 2 +- .../kibana_usage_collection/tsconfig.json | 1 - src/plugins/telemetry/public/plugin.test.ts | 2 +- src/plugins/telemetry/public/plugin.ts | 2 +- src/plugins/telemetry/server/plugin.test.ts | 2 +- src/plugins/telemetry/server/plugin.ts | 2 +- src/plugins/telemetry/tsconfig.json | 3 +- .../server/collector/types.ts | 4 +- src/plugins/usage_collection/tsconfig.json | 2 +- .../common/fetch_events.ts | 2 +- .../analytics_ftr_helpers/common/types.ts | 2 +- .../public/custom_shipper.ts | 3 +- .../server/custom_shipper.ts | 3 +- .../analytics_ftr_helpers/tsconfig.json | 2 +- .../core_overall_status_changed.ts | 2 +- test/tsconfig.json | 1 - tsconfig.base.json | 12 +- ...r_cloud_deployment_id_analytics_context.ts | 2 +- x-pack/plugins/cloud/tsconfig.json | 2 +- .../cloud_full_story/public/plugin.ts | 2 +- .../cloud_full_story/tsconfig.json | 2 +- .../lib/telemetry/event_based_telemetry.ts | 2 +- .../plugins/elastic_assistant/tsconfig.json | 1 - .../services/telemetry/fleet_usages_schema.ts | 2 +- x-pack/plugins/fleet/tsconfig.json | 1 - .../public/telemetry/event_types.ts | 3 +- .../plugins/global_search_bar/tsconfig.json | 1 - .../register_analytics_context_provider.ts | 2 +- x-pack/plugins/licensing/tsconfig.json | 4 +- .../apm/public/services/telemetry/types.ts | 3 +- .../observability_solution/apm/tsconfig.json | 1 - .../infra/public/services/telemetry/types.ts | 3 +- .../infra/tsconfig.json | 1 - .../public/analytics/schemas/chat_feedback.ts | 2 +- .../public/analytics/schemas/common.ts | 2 +- .../analytics/schemas/insight_feedback.ts | 2 +- .../analytics/schemas/user_sent_prompt.ts | 2 +- .../server/analytics/recall_ranking.ts | 2 +- .../observability_ai_assistant/tsconfig.json | 1 - .../common/telemetry_events.ts | 2 +- .../observability_logs_explorer/tsconfig.json | 2 +- .../common/telemetry_events.ts | 2 +- .../observability_onboarding/tsconfig.json | 4 +- .../server/usage/register_event_types.ts | 4 +- x-pack/plugins/reporting/tsconfig.json | 1 - .../server/analytics/events.ts | 2 +- .../plugins/search_playground/tsconfig.json | 1 - .../server/analytics/analytics_service.ts | 7 +- x-pack/plugins/security/tsconfig.json | 1 - .../telemetry/events/ai_assistant/types.ts | 2 +- .../telemetry/events/alerts_grouping/types.ts | 2 +- .../events/attack_discovery/types.ts | 2 +- .../telemetry/events/data_quality/types.ts | 2 +- .../events/document_details/types.ts | 2 +- .../events/entity_analytics/types.ts | 2 +- .../lib/telemetry/events/onboarding/types.ts | 2 +- .../public/common/lib/telemetry/types.ts | 3 +- .../query_tab_unified_components.test.tsx | 2 +- .../unified_components/index.test.tsx | 4 +- .../lib/telemetry/event_based/events.ts | 2 +- .../plugins/security_solution/tsconfig.json | 1 - .../server/telemetry/event_based_telemetry.ts | 2 +- .../tsconfig.json | 1 - yarn.lock | 24 +- 181 files changed, 1446 insertions(+), 1612 deletions(-) delete mode 100644 packages/analytics/README.md create mode 100644 packages/analytics/ebt/README.md rename packages/analytics/{ => ebt}/client/README.md (99%) rename packages/analytics/{ => ebt}/client/index.ts (98%) rename packages/analytics/{ => ebt}/client/src/analytics_client/analytics_client.test.ts (65%) rename packages/analytics/{ => ebt}/client/src/analytics_client/analytics_client.ts (100%) rename packages/analytics/{ => ebt}/client/src/analytics_client/context_service.test.ts (100%) rename packages/analytics/{ => ebt}/client/src/analytics_client/context_service.ts (100%) rename packages/analytics/{ => ebt}/client/src/analytics_client/index.ts (100%) rename packages/analytics/{ => ebt}/client/src/analytics_client/mocks.ts (100%) rename packages/analytics/{ => ebt}/client/src/analytics_client/opt_in_config.test.ts (100%) rename packages/analytics/{ => ebt}/client/src/analytics_client/opt_in_config.ts (100%) rename packages/analytics/{ => ebt}/client/src/analytics_client/shippers_registry.test.ts (100%) rename packages/analytics/{ => ebt}/client/src/analytics_client/shippers_registry.ts (100%) rename packages/analytics/{ => ebt}/client/src/analytics_client/types.ts (100%) rename packages/analytics/{ => ebt}/client/src/events/index.ts (100%) rename packages/analytics/{ => ebt}/client/src/events/types.ts (100%) rename packages/analytics/{ => ebt}/client/src/mocks.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/index.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/types.test.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/types.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/validation/excess.test.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/validation/excess.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/validation/index.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/validation/schema_to_io_ts.test.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/validation/schema_to_io_ts.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/validation/validate_schema.test.ts (100%) rename packages/analytics/{ => ebt}/client/src/schema/validation/validate_schema.ts (100%) rename packages/analytics/{ => ebt}/client/src/shippers/index.ts (100%) rename packages/analytics/{ => ebt}/client/src/shippers/mocks.ts (100%) rename packages/analytics/{ => ebt}/client/src/shippers/types.ts (100%) create mode 100644 packages/analytics/ebt/index.ts rename packages/analytics/{client => ebt}/jest.config.js (77%) rename packages/analytics/{client => ebt}/kibana.jsonc (66%) rename packages/analytics/{client => ebt}/package.json (59%) rename packages/analytics/{ => ebt}/shippers/README.md (91%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/browser/README.md (79%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/browser/index.ts (82%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/browser/src/browser_shipper.test.ts (51%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/browser/src/browser_shipper.ts (95%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/README.md (73%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/index.ts (100%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/build_headers.test.ts (100%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/build_headers.ts (100%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/build_url.test.ts (100%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/build_url.ts (100%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/error_with_code.test.ts (100%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/error_with_code.ts (100%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/events_to_ndjson.test.ts (96%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/events_to_ndjson.ts (92%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/report_telemetry_counters.test.ts (98%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/report_telemetry_counters.ts (98%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/common/src/types.ts (100%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/server/README.md (83%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/server/index.ts (82%) rename packages/analytics/{ => ebt}/shippers/elastic_v3/server/src/server_shipper.test.mocks.ts (100%) create mode 100644 packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.test.ts rename packages/analytics/{ => ebt}/shippers/elastic_v3/server/src/server_shipper.ts (99%) rename packages/analytics/{ => ebt}/shippers/fullstory/README.md (91%) rename packages/analytics/{ => ebt}/shippers/fullstory/index.ts (100%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/format_payload.test.ts (100%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/format_payload.ts (100%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/fullstory_shipper.test.mocks.ts (100%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/fullstory_shipper.test.ts (100%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/fullstory_shipper.ts (96%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/get_parsed_version.test.ts (100%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/get_parsed_version.ts (100%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/load_snippet.test.ts (68%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/load_snippet.ts (100%) rename packages/analytics/{ => ebt}/shippers/fullstory/src/types.ts (100%) rename packages/analytics/{client => ebt}/tsconfig.json (63%) delete mode 100644 packages/analytics/shippers/elastic_v3/browser/jest.config.js delete mode 100644 packages/analytics/shippers/elastic_v3/browser/kibana.jsonc delete mode 100644 packages/analytics/shippers/elastic_v3/browser/package.json delete mode 100644 packages/analytics/shippers/elastic_v3/browser/tsconfig.json delete mode 100644 packages/analytics/shippers/elastic_v3/common/jest.config.js delete mode 100644 packages/analytics/shippers/elastic_v3/common/kibana.jsonc delete mode 100644 packages/analytics/shippers/elastic_v3/common/package.json delete mode 100644 packages/analytics/shippers/elastic_v3/common/tsconfig.json delete mode 100644 packages/analytics/shippers/elastic_v3/server/jest.config.js delete mode 100644 packages/analytics/shippers/elastic_v3/server/kibana.jsonc delete mode 100644 packages/analytics/shippers/elastic_v3/server/package.json delete mode 100644 packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.ts delete mode 100644 packages/analytics/shippers/elastic_v3/server/tsconfig.json delete mode 100644 packages/analytics/shippers/fullstory/jest.config.js delete mode 100644 packages/analytics/shippers/fullstory/kibana.jsonc delete mode 100644 packages/analytics/shippers/fullstory/package.json delete mode 100644 packages/analytics/shippers/fullstory/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 44c2a4f27636bb..a5fc58216acbfb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -35,14 +35,9 @@ packages/kbn-ambient-ftr-types @elastic/kibana-operations @elastic/appex-qa packages/kbn-ambient-storybook-types @elastic/kibana-operations packages/kbn-ambient-ui-types @elastic/kibana-operations packages/kbn-analytics @elastic/kibana-core -packages/analytics/client @elastic/kibana-core packages/analytics/utils/analytics_collection_utils @elastic/kibana-core test/analytics/plugins/analytics_ftr_helpers @elastic/kibana-core test/analytics/plugins/analytics_plugin_a @elastic/kibana-core -packages/analytics/shippers/elastic_v3/browser @elastic/kibana-core -packages/analytics/shippers/elastic_v3/common @elastic/kibana-core -packages/analytics/shippers/elastic_v3/server @elastic/kibana-core -packages/analytics/shippers/fullstory @elastic/kibana-core packages/kbn-apm-config-loader @elastic/kibana-core @vigneshshanmugam x-pack/plugins/observability_solution/apm_data_access @elastic/obs-knowledge-team @elastic/obs-ux-infra_services-team packages/kbn-apm-data-view @elastic/obs-ux-infra_services-team @@ -378,6 +373,7 @@ packages/kbn-discover-utils @elastic/kibana-data-discovery packages/kbn-doc-links @elastic/docs packages/kbn-docs-utils @elastic/kibana-operations packages/kbn-dom-drag-drop @elastic/kibana-visualizations @elastic/kibana-data-discovery +packages/analytics/ebt @elastic/kibana-core packages/kbn-ebt-tools @elastic/kibana-core x-pack/packages/security-solution/ecs_data_quality_dashboard @elastic/security-threat-hunting-explore x-pack/plugins/ecs_data_quality_dashboard @elastic/security-threat-hunting-explore diff --git a/package.json b/package.json index eaae0b675e62e3..d8934593517833 100644 --- a/package.json +++ b/package.json @@ -166,14 +166,9 @@ "@kbn/alerts-restricted-fixtures-plugin": "link:x-pack/test/alerting_api_integration/common/plugins/alerts_restricted", "@kbn/alerts-ui-shared": "link:packages/kbn-alerts-ui-shared", "@kbn/analytics": "link:packages/kbn-analytics", - "@kbn/analytics-client": "link:packages/analytics/client", "@kbn/analytics-collection-utils": "link:packages/analytics/utils/analytics_collection_utils", "@kbn/analytics-ftr-helpers-plugin": "link:test/analytics/plugins/analytics_ftr_helpers", "@kbn/analytics-plugin-a-plugin": "link:test/analytics/plugins/analytics_plugin_a", - "@kbn/analytics-shippers-elastic-v3-browser": "link:packages/analytics/shippers/elastic_v3/browser", - "@kbn/analytics-shippers-elastic-v3-common": "link:packages/analytics/shippers/elastic_v3/common", - "@kbn/analytics-shippers-elastic-v3-server": "link:packages/analytics/shippers/elastic_v3/server", - "@kbn/analytics-shippers-fullstory": "link:packages/analytics/shippers/fullstory", "@kbn/apm-config-loader": "link:packages/kbn-apm-config-loader", "@kbn/apm-data-access-plugin": "link:x-pack/plugins/observability_solution/apm_data_access", "@kbn/apm-data-view": "link:packages/kbn-apm-data-view", @@ -433,6 +428,7 @@ "@kbn/discover-utils": "link:packages/kbn-discover-utils", "@kbn/doc-links": "link:packages/kbn-doc-links", "@kbn/dom-drag-drop": "link:packages/kbn-dom-drag-drop", + "@kbn/ebt": "link:packages/analytics/ebt", "@kbn/ebt-tools": "link:packages/kbn-ebt-tools", "@kbn/ecs-data-quality-dashboard": "link:x-pack/packages/security-solution/ecs_data_quality_dashboard", "@kbn/ecs-data-quality-dashboard-plugin": "link:x-pack/plugins/ecs_data_quality_dashboard", diff --git a/packages/analytics/README.md b/packages/analytics/README.md deleted file mode 100644 index a9198dae88975a..00000000000000 --- a/packages/analytics/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# @kbn/analytics-* - -This module implements the Analytics client used for Event-Based Telemetry. The intention of the client is to be usable on both: the UI and the Server sides. - -## Client - -Holds the public APIs to report events, enrich the events' context and set up the transport mechanisms. Refer to the [client's docs](./client/README.md) for more information. - -## Prebuilt shippers - -Elastic-approved shippers are available as `@kbn/analytics-shippers-*` packages. Refer to the [shippers' docs](./shippers/README.md) for more information. diff --git a/packages/analytics/ebt/README.md b/packages/analytics/ebt/README.md new file mode 100644 index 00000000000000..8758a90304cbab --- /dev/null +++ b/packages/analytics/ebt/README.md @@ -0,0 +1,11 @@ +# @kbn/ebt/* + +This module implements the Analytics client used for Event-Based Telemetry. The intention of the client is to be usable on both: the UI and the Server sides. + +## Client + +`@kbn/ebt/client` holds the public APIs to report events, enrich the events' context and set up the transport mechanisms. Refer to the [client's docs](./client/README.md) for more information. + +## Prebuilt shippers + +Elastic-approved shippers are available as `@kbn/ebt/shippers/*` packages. Refer to the [shippers' docs](./shippers/README.md) for more information. diff --git a/packages/analytics/client/README.md b/packages/analytics/ebt/client/README.md similarity index 99% rename from packages/analytics/client/README.md rename to packages/analytics/ebt/client/README.md index e51795faa6a03a..508fc984c1a58d 100644 --- a/packages/analytics/client/README.md +++ b/packages/analytics/ebt/client/README.md @@ -1,4 +1,4 @@ -# @kbn/analytics-client +# @kbn/ebt/client This module implements the Analytics client used for Event-Based Telemetry. The intention of the client is to be usable on both: the UI and the Server sides. @@ -7,7 +7,7 @@ This module implements the Analytics client used for Event-Based Telemetry. The It all starts by creating the client with the `createAnalytics` API: ```typescript -import { createAnalytics } from '@kbn/analytics-client'; +import { createAnalytics } from '@kbn/ebt/client'; const analytics = createAnalytics({ // Set to `true` when running in developer mode. @@ -167,7 +167,7 @@ import type { EventContext, IShipper, TelemetryCounter -} from '@kbn/analytics-client'; +} from '@kbn/ebt/client'; class MyVeryOwnShipper implements IShipper { constructor(myOptions: MyOptions, initContext: AnalyticsClientInitContext) { diff --git a/packages/analytics/client/index.ts b/packages/analytics/ebt/client/index.ts similarity index 98% rename from packages/analytics/client/index.ts rename to packages/analytics/ebt/client/index.ts index 4354d1f2d0cfdd..7127a21a5517ec 100644 --- a/packages/analytics/client/index.ts +++ b/packages/analytics/ebt/client/index.ts @@ -33,6 +33,7 @@ export type { ShipperName, // Types for the registerContextProvider API ContextProviderOpts, + ContextProviderName, // Types for the registerEventType API EventTypeOpts, } from './src/analytics_client'; diff --git a/packages/analytics/client/src/analytics_client/analytics_client.test.ts b/packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts similarity index 65% rename from packages/analytics/client/src/analytics_client/analytics_client.test.ts rename to packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts index 650b1e1b4e750e..0d72f003e77a6d 100644 --- a/packages/analytics/client/src/analytics_client/analytics_client.test.ts +++ b/packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts @@ -8,7 +8,6 @@ // eslint-disable-next-line max-classes-per-file import { Subject, lastValueFrom, take, toArray } from 'rxjs'; -import { fakeSchedulers } from 'rxjs-marbles/jest'; import type { MockedLogger } from '@kbn/logging-mocks'; import { loggerMock } from '@kbn/logging-mocks'; import { AnalyticsClient } from './analytics_client'; @@ -21,7 +20,7 @@ describe('AnalyticsClient', () => { let logger: MockedLogger; beforeEach(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); + jest.useFakeTimers(); logger = loggerMock.create(); analyticsClient = new AnalyticsClient({ logger, @@ -338,76 +337,67 @@ describe('AnalyticsClient', () => { expect(optIn).toHaveBeenCalledWith(true); }); - test( - 'Spreads the context updates to the shipper (only after opt-in)', - fakeSchedulers((advance) => { - const extendContextMock = jest.fn(); - analyticsClient.registerShipper(MockedShipper, { extendContextMock }); - expect(extendContextMock).toHaveBeenCalledTimes(0); // Not until we have opt-in - analyticsClient.optIn({ global: { enabled: true } }); - advance(10); - expect(extendContextMock).toHaveBeenCalledWith({}); // The initial context - - const context$ = new Subject<{ a_field: boolean }>(); - analyticsClient.registerContextProvider({ - name: 'contextProviderA', - schema: { - a_field: { - type: 'boolean', - _meta: { - description: 'a_field description', - }, + test('Spreads the context updates to the shipper (only after opt-in)', async () => { + const extendContextMock = jest.fn(); + analyticsClient.registerShipper(MockedShipper, { extendContextMock }); + expect(extendContextMock).toHaveBeenCalledTimes(0); // Not until we have opt-in + analyticsClient.optIn({ global: { enabled: true } }); + await jest.advanceTimersByTimeAsync(10); + expect(extendContextMock).toHaveBeenCalledWith({}); // The initial context + + const context$ = new Subject<{ a_field: boolean }>(); + analyticsClient.registerContextProvider({ + name: 'contextProviderA', + schema: { + a_field: { + type: 'boolean', + _meta: { + description: 'a_field description', }, }, - context$, - }); + }, + context$, + }); - context$.next({ a_field: true }); - expect(extendContextMock).toHaveBeenCalledWith({ a_field: true }); // After update - }) - ); - - test( - 'Does not spread the context if opt-in === false', - fakeSchedulers((advance) => { - const extendContextMock = jest.fn(); - analyticsClient.registerShipper(MockedShipper, { extendContextMock }); - expect(extendContextMock).toHaveBeenCalledTimes(0); // Not until we have opt-in - analyticsClient.optIn({ global: { enabled: false } }); - advance(10); - expect(extendContextMock).toHaveBeenCalledTimes(0); // Not until we have opt-in - }) - ); - - test( - 'Handles errors in the shipper', - fakeSchedulers(async (advance) => { - const optInMock = jest.fn().mockImplementation(() => { - throw new Error('Something went terribly wrong'); - }); - const extendContextMock = jest.fn().mockImplementation(() => { - throw new Error('Something went terribly wrong'); - }); - const shutdownMock = jest.fn().mockImplementation(() => { - throw new Error('Something went terribly wrong'); - }); - analyticsClient.registerShipper(MockedShipper, { - optInMock, - extendContextMock, - shutdownMock, - }); - expect(() => analyticsClient.optIn({ global: { enabled: true } })).not.toThrow(); - advance(10); - expect(optInMock).toHaveBeenCalledWith(true); - expect(extendContextMock).toHaveBeenCalledWith({}); // The initial context - expect(logger.warn).toHaveBeenCalledWith( - `Shipper "${MockedShipper.shipperName}" failed to extend the context`, - expect.any(Error) - ); - await expect(analyticsClient.shutdown()).resolves.toBeUndefined(); - expect(shutdownMock).toHaveBeenCalled(); - }) - ); + context$.next({ a_field: true }); + expect(extendContextMock).toHaveBeenCalledWith({ a_field: true }); // After update + }); + + test('Does not spread the context if opt-in === false', async () => { + const extendContextMock = jest.fn(); + analyticsClient.registerShipper(MockedShipper, { extendContextMock }); + expect(extendContextMock).toHaveBeenCalledTimes(0); // Not until we have opt-in + analyticsClient.optIn({ global: { enabled: false } }); + await jest.advanceTimersByTimeAsync(10); + expect(extendContextMock).toHaveBeenCalledTimes(0); // Not until we have opt-in + }); + + test('Handles errors in the shipper', async () => { + const optInMock = jest.fn().mockImplementation(() => { + throw new Error('Something went terribly wrong'); + }); + const extendContextMock = jest.fn().mockImplementation(() => { + throw new Error('Something went terribly wrong'); + }); + const shutdownMock = jest.fn().mockImplementation(() => { + throw new Error('Something went terribly wrong'); + }); + analyticsClient.registerShipper(MockedShipper, { + optInMock, + extendContextMock, + shutdownMock, + }); + expect(() => analyticsClient.optIn({ global: { enabled: true } })).not.toThrow(); + await jest.advanceTimersByTimeAsync(10); + expect(optInMock).toHaveBeenCalledWith(true); + expect(extendContextMock).toHaveBeenCalledWith({}); // The initial context + expect(logger.warn).toHaveBeenCalledWith( + `Shipper "${MockedShipper.shipperName}" failed to extend the context`, + expect.any(Error) + ); + await expect(analyticsClient.shutdown()).resolves.toBeUndefined(); + expect(shutdownMock).toHaveBeenCalled(); + }); }); describe('ContextProvider APIs', () => { @@ -633,89 +623,86 @@ describe('AnalyticsClient', () => { ]); }); - test( - 'Sends events from the internal queue when there are shippers and an opt-in response is true', - fakeSchedulers(async (advance) => { - const telemetryCounterPromise = lastValueFrom( - analyticsClient.telemetryCounter$.pipe(take(3 + 2), toArray()) // Waiting for 3 enqueued + 2 batch-shipped events - ); - - // Send multiple events of 1 type to test the grouping logic as well - analyticsClient.reportEvent('event-type-a', { a_field: 'a' }); - analyticsClient.reportEvent('event-type-b', { b_field: 100 }); - analyticsClient.reportEvent('event-type-a', { a_field: 'b' }); - - // As proven in the previous test, the events are still enqueued. - // Let's register a shipper and opt-in to test the dequeue logic. - const reportEventsMock = jest.fn(); - analyticsClient.registerShipper(MockedShipper1, { reportEventsMock }); - analyticsClient.optIn({ global: { enabled: true } }); - advance(10); - - expect(reportEventsMock).toHaveBeenCalledTimes(2); - expect(reportEventsMock).toHaveBeenNthCalledWith(1, [ - { - context: {}, - event_type: 'event-type-a', - properties: { a_field: 'a' }, - timestamp: expect.any(String), - }, - { - context: {}, - event_type: 'event-type-a', - properties: { a_field: 'b' }, - timestamp: expect.any(String), - }, - ]); - expect(reportEventsMock).toHaveBeenNthCalledWith(2, [ - { - context: {}, - event_type: 'event-type-b', - properties: { b_field: 100 }, - timestamp: expect.any(String), - }, - ]); - - // Expect 3 enqueued events, and 2 sent_to_shipper batched requests - await expect(telemetryCounterPromise).resolves.toEqual([ - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-a', - code: 'enqueued', - count: 1, - }, - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-b', - code: 'enqueued', - count: 1, - }, - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-a', - code: 'enqueued', - count: 1, - }, - { - type: 'sent_to_shipper', - source: 'client', - event_type: 'event-type-a', - code: 'OK', - count: 2, - }, - { - type: 'sent_to_shipper', - source: 'client', - event_type: 'event-type-b', - code: 'OK', - count: 1, - }, - ]); - }) - ); + test('Sends events from the internal queue when there are shippers and an opt-in response is true', async () => { + const telemetryCounterPromise = lastValueFrom( + analyticsClient.telemetryCounter$.pipe(take(3 + 2), toArray()) // Waiting for 3 enqueued + 2 batch-shipped events + ); + + // Send multiple events of 1 type to test the grouping logic as well + analyticsClient.reportEvent('event-type-a', { a_field: 'a' }); + analyticsClient.reportEvent('event-type-b', { b_field: 100 }); + analyticsClient.reportEvent('event-type-a', { a_field: 'b' }); + + // As proven in the previous test, the events are still enqueued. + // Let's register a shipper and opt-in to test the dequeue logic. + const reportEventsMock = jest.fn(); + analyticsClient.registerShipper(MockedShipper1, { reportEventsMock }); + analyticsClient.optIn({ global: { enabled: true } }); + await jest.advanceTimersByTimeAsync(10); + + expect(reportEventsMock).toHaveBeenCalledTimes(2); + expect(reportEventsMock).toHaveBeenNthCalledWith(1, [ + { + context: {}, + event_type: 'event-type-a', + properties: { a_field: 'a' }, + timestamp: expect.any(String), + }, + { + context: {}, + event_type: 'event-type-a', + properties: { a_field: 'b' }, + timestamp: expect.any(String), + }, + ]); + expect(reportEventsMock).toHaveBeenNthCalledWith(2, [ + { + context: {}, + event_type: 'event-type-b', + properties: { b_field: 100 }, + timestamp: expect.any(String), + }, + ]); + + // Expect 3 enqueued events, and 2 sent_to_shipper batched requests + await expect(telemetryCounterPromise).resolves.toEqual([ + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-a', + code: 'enqueued', + count: 1, + }, + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-b', + code: 'enqueued', + count: 1, + }, + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-a', + code: 'enqueued', + count: 1, + }, + { + type: 'sent_to_shipper', + source: 'client', + event_type: 'event-type-a', + code: 'OK', + count: 2, + }, + { + type: 'sent_to_shipper', + source: 'client', + event_type: 'event-type-b', + code: 'OK', + count: 1, + }, + ]); + }); test('Discards events from the internal queue when there are shippers and an opt-in response is false', async () => { const telemetryCounterPromise = lastValueFrom( @@ -823,259 +810,250 @@ describe('AnalyticsClient', () => { expect(analyticsClient['internalEventQueue$'].observed).toBe(false); }); - test( - 'Discards only one type of the enqueued events based on event_type config', - fakeSchedulers(async (advance) => { - const telemetryCounterPromise = lastValueFrom( - analyticsClient.telemetryCounter$.pipe(take(3 + 1), toArray()) // Waiting for 3 enqueued + 1 batch-shipped events - ); - - // Send multiple events of 1 type to test the grouping logic as well - analyticsClient.reportEvent('event-type-a', { a_field: 'a' }); - analyticsClient.reportEvent('event-type-b', { b_field: 100 }); - analyticsClient.reportEvent('event-type-a', { a_field: 'b' }); - - const reportEventsMock = jest.fn(); - analyticsClient.registerShipper(MockedShipper1, { reportEventsMock }); - analyticsClient.optIn({ - global: { enabled: true }, - event_types: { ['event-type-a']: { enabled: false } }, - }); - advance(10); - - expect(reportEventsMock).toHaveBeenCalledTimes(1); - expect(reportEventsMock).toHaveBeenNthCalledWith(1, [ - { - context: {}, - event_type: 'event-type-b', - properties: { b_field: 100 }, - timestamp: expect.any(String), - }, - ]); - - // Expect 3 enqueued events, and 1 sent_to_shipper batched request - await expect(telemetryCounterPromise).resolves.toEqual([ - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-a', - code: 'enqueued', - count: 1, - }, - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-b', - code: 'enqueued', - count: 1, - }, - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-a', - code: 'enqueued', - count: 1, - }, - { - type: 'sent_to_shipper', - source: 'client', - event_type: 'event-type-b', - code: 'OK', - count: 1, - }, - ]); - }) - ); - - test( - 'Discards the event at the shipper level (for a specific event)', - fakeSchedulers(async (advance) => { - const telemetryCounterPromise = lastValueFrom( - analyticsClient.telemetryCounter$.pipe(take(3 + 2), toArray()) // Waiting for 3 enqueued + 2 batch-shipped events - ); - - // Send multiple events of 1 type to test the grouping logic as well - analyticsClient.reportEvent('event-type-a', { a_field: 'a' }); - analyticsClient.reportEvent('event-type-b', { b_field: 100 }); - analyticsClient.reportEvent('event-type-a', { a_field: 'b' }); - - // Register 2 shippers and set 1 of them as disabled for event-type-a - const reportEventsMock1 = jest.fn(); - const reportEventsMock2 = jest.fn(); - analyticsClient.registerShipper(MockedShipper1, { reportEventsMock: reportEventsMock1 }); - analyticsClient.registerShipper(MockedShipper2, { reportEventsMock: reportEventsMock2 }); - analyticsClient.optIn({ - global: { enabled: true }, - event_types: { - ['event-type-a']: { enabled: true, shippers: { [MockedShipper2.shipperName]: false } }, - }, - }); - advance(10); - - expect(reportEventsMock1).toHaveBeenCalledTimes(2); - expect(reportEventsMock1).toHaveBeenNthCalledWith(1, [ - { - context: {}, - event_type: 'event-type-a', - properties: { a_field: 'a' }, - timestamp: expect.any(String), - }, - { - context: {}, - event_type: 'event-type-a', - properties: { a_field: 'b' }, - timestamp: expect.any(String), - }, - ]); - expect(reportEventsMock1).toHaveBeenNthCalledWith(2, [ - { - context: {}, - event_type: 'event-type-b', - properties: { b_field: 100 }, - timestamp: expect.any(String), - }, - ]); - expect(reportEventsMock2).toHaveBeenCalledTimes(1); - expect(reportEventsMock2).toHaveBeenNthCalledWith(1, [ - { - context: {}, - event_type: 'event-type-b', - properties: { b_field: 100 }, - timestamp: expect.any(String), - }, - ]); - - // Expect 3 enqueued events, and 2 sent_to_shipper batched requests - await expect(telemetryCounterPromise).resolves.toEqual([ - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-a', - code: 'enqueued', - count: 1, - }, - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-b', - code: 'enqueued', - count: 1, - }, - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-a', - code: 'enqueued', - count: 1, - }, - { - type: 'sent_to_shipper', - source: 'client', - event_type: 'event-type-a', - code: 'OK', - count: 2, - }, - { - type: 'sent_to_shipper', - source: 'client', - event_type: 'event-type-b', - code: 'OK', - count: 1, - }, - ]); - }) - ); - - test( - 'Discards all the events at the shipper level (globally disabled)', - fakeSchedulers(async (advance) => { - const telemetryCounterPromise = lastValueFrom( - analyticsClient.telemetryCounter$.pipe(take(3 + 2), toArray()) // Waiting for 3 enqueued + 2 batch-shipped events - ); - - // Send multiple events of 1 type to test the grouping logic as well - analyticsClient.reportEvent('event-type-a', { a_field: 'a' }); - analyticsClient.reportEvent('event-type-b', { b_field: 100 }); - analyticsClient.reportEvent('event-type-a', { a_field: 'b' }); - - // Register 2 shippers and set 1 of them as globally disabled - const reportEventsMock1 = jest.fn(); - const reportEventsMock2 = jest.fn(); - analyticsClient.registerShipper(MockedShipper1, { reportEventsMock: reportEventsMock1 }); - analyticsClient.registerShipper(MockedShipper2, { reportEventsMock: reportEventsMock2 }); - analyticsClient.optIn({ - global: { enabled: true, shippers: { [MockedShipper2.shipperName]: false } }, - event_types: { - ['event-type-a']: { enabled: true }, - }, - }); - advance(10); - - expect(reportEventsMock1).toHaveBeenCalledTimes(2); - expect(reportEventsMock1).toHaveBeenNthCalledWith(1, [ - { - context: {}, - event_type: 'event-type-a', - properties: { a_field: 'a' }, - timestamp: expect.any(String), - }, - { - context: {}, - event_type: 'event-type-a', - properties: { a_field: 'b' }, - timestamp: expect.any(String), - }, - ]); - expect(reportEventsMock1).toHaveBeenNthCalledWith(2, [ - { - context: {}, - event_type: 'event-type-b', - properties: { b_field: 100 }, - timestamp: expect.any(String), - }, - ]); - expect(reportEventsMock2).toHaveBeenCalledTimes(0); - - // Expect 3 enqueued events, and 2 sent_to_shipper batched requests - await expect(telemetryCounterPromise).resolves.toEqual([ - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-a', - code: 'enqueued', - count: 1, - }, - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-b', - code: 'enqueued', - count: 1, - }, - { - type: 'enqueued', - source: 'client', - event_type: 'event-type-a', - code: 'enqueued', - count: 1, - }, - { - type: 'sent_to_shipper', - source: 'client', - event_type: 'event-type-a', - code: 'OK', - count: 2, - }, - { - type: 'sent_to_shipper', - source: 'client', - event_type: 'event-type-b', - code: 'OK', - count: 1, - }, - ]); - }) - ); + test('Discards only one type of the enqueued events based on event_type config', async () => { + const telemetryCounterPromise = lastValueFrom( + analyticsClient.telemetryCounter$.pipe(take(3 + 1), toArray()) // Waiting for 3 enqueued + 1 batch-shipped events + ); + + // Send multiple events of 1 type to test the grouping logic as well + analyticsClient.reportEvent('event-type-a', { a_field: 'a' }); + analyticsClient.reportEvent('event-type-b', { b_field: 100 }); + analyticsClient.reportEvent('event-type-a', { a_field: 'b' }); + + const reportEventsMock = jest.fn(); + analyticsClient.registerShipper(MockedShipper1, { reportEventsMock }); + analyticsClient.optIn({ + global: { enabled: true }, + event_types: { ['event-type-a']: { enabled: false } }, + }); + await jest.advanceTimersByTimeAsync(10); + + expect(reportEventsMock).toHaveBeenCalledTimes(1); + expect(reportEventsMock).toHaveBeenNthCalledWith(1, [ + { + context: {}, + event_type: 'event-type-b', + properties: { b_field: 100 }, + timestamp: expect.any(String), + }, + ]); + + // Expect 3 enqueued events, and 1 sent_to_shipper batched request + await expect(telemetryCounterPromise).resolves.toEqual([ + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-a', + code: 'enqueued', + count: 1, + }, + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-b', + code: 'enqueued', + count: 1, + }, + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-a', + code: 'enqueued', + count: 1, + }, + { + type: 'sent_to_shipper', + source: 'client', + event_type: 'event-type-b', + code: 'OK', + count: 1, + }, + ]); + }); + + test('Discards the event at the shipper level (for a specific event)', async () => { + const telemetryCounterPromise = lastValueFrom( + analyticsClient.telemetryCounter$.pipe(take(3 + 2), toArray()) // Waiting for 3 enqueued + 2 batch-shipped events + ); + + // Send multiple events of 1 type to test the grouping logic as well + analyticsClient.reportEvent('event-type-a', { a_field: 'a' }); + analyticsClient.reportEvent('event-type-b', { b_field: 100 }); + analyticsClient.reportEvent('event-type-a', { a_field: 'b' }); + + // Register 2 shippers and set 1 of them as disabled for event-type-a + const reportEventsMock1 = jest.fn(); + const reportEventsMock2 = jest.fn(); + analyticsClient.registerShipper(MockedShipper1, { reportEventsMock: reportEventsMock1 }); + analyticsClient.registerShipper(MockedShipper2, { reportEventsMock: reportEventsMock2 }); + analyticsClient.optIn({ + global: { enabled: true }, + event_types: { + ['event-type-a']: { enabled: true, shippers: { [MockedShipper2.shipperName]: false } }, + }, + }); + await jest.advanceTimersByTimeAsync(10); + + expect(reportEventsMock1).toHaveBeenCalledTimes(2); + expect(reportEventsMock1).toHaveBeenNthCalledWith(1, [ + { + context: {}, + event_type: 'event-type-a', + properties: { a_field: 'a' }, + timestamp: expect.any(String), + }, + { + context: {}, + event_type: 'event-type-a', + properties: { a_field: 'b' }, + timestamp: expect.any(String), + }, + ]); + expect(reportEventsMock1).toHaveBeenNthCalledWith(2, [ + { + context: {}, + event_type: 'event-type-b', + properties: { b_field: 100 }, + timestamp: expect.any(String), + }, + ]); + expect(reportEventsMock2).toHaveBeenCalledTimes(1); + expect(reportEventsMock2).toHaveBeenNthCalledWith(1, [ + { + context: {}, + event_type: 'event-type-b', + properties: { b_field: 100 }, + timestamp: expect.any(String), + }, + ]); + + // Expect 3 enqueued events, and 2 sent_to_shipper batched requests + await expect(telemetryCounterPromise).resolves.toEqual([ + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-a', + code: 'enqueued', + count: 1, + }, + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-b', + code: 'enqueued', + count: 1, + }, + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-a', + code: 'enqueued', + count: 1, + }, + { + type: 'sent_to_shipper', + source: 'client', + event_type: 'event-type-a', + code: 'OK', + count: 2, + }, + { + type: 'sent_to_shipper', + source: 'client', + event_type: 'event-type-b', + code: 'OK', + count: 1, + }, + ]); + }); + + test('Discards all the events at the shipper level (globally disabled)', async () => { + const telemetryCounterPromise = lastValueFrom( + analyticsClient.telemetryCounter$.pipe(take(3 + 2), toArray()) // Waiting for 3 enqueued + 2 batch-shipped events + ); + + // Send multiple events of 1 type to test the grouping logic as well + analyticsClient.reportEvent('event-type-a', { a_field: 'a' }); + analyticsClient.reportEvent('event-type-b', { b_field: 100 }); + analyticsClient.reportEvent('event-type-a', { a_field: 'b' }); + + // Register 2 shippers and set 1 of them as globally disabled + const reportEventsMock1 = jest.fn(); + const reportEventsMock2 = jest.fn(); + analyticsClient.registerShipper(MockedShipper1, { reportEventsMock: reportEventsMock1 }); + analyticsClient.registerShipper(MockedShipper2, { reportEventsMock: reportEventsMock2 }); + analyticsClient.optIn({ + global: { enabled: true, shippers: { [MockedShipper2.shipperName]: false } }, + event_types: { + ['event-type-a']: { enabled: true }, + }, + }); + await jest.advanceTimersByTimeAsync(10); + + expect(reportEventsMock1).toHaveBeenCalledTimes(2); + expect(reportEventsMock1).toHaveBeenNthCalledWith(1, [ + { + context: {}, + event_type: 'event-type-a', + properties: { a_field: 'a' }, + timestamp: expect.any(String), + }, + { + context: {}, + event_type: 'event-type-a', + properties: { a_field: 'b' }, + timestamp: expect.any(String), + }, + ]); + expect(reportEventsMock1).toHaveBeenNthCalledWith(2, [ + { + context: {}, + event_type: 'event-type-b', + properties: { b_field: 100 }, + timestamp: expect.any(String), + }, + ]); + expect(reportEventsMock2).toHaveBeenCalledTimes(0); + + // Expect 3 enqueued events, and 2 sent_to_shipper batched requests + await expect(telemetryCounterPromise).resolves.toEqual([ + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-a', + code: 'enqueued', + count: 1, + }, + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-b', + code: 'enqueued', + count: 1, + }, + { + type: 'enqueued', + source: 'client', + event_type: 'event-type-a', + code: 'enqueued', + count: 1, + }, + { + type: 'sent_to_shipper', + source: 'client', + event_type: 'event-type-a', + code: 'OK', + count: 2, + }, + { + type: 'sent_to_shipper', + source: 'client', + event_type: 'event-type-b', + code: 'OK', + count: 1, + }, + ]); + }); test('Discards incoming events when opt-in response is false', async () => { // Set OptIn and shipper first to test the "once-set up" scenario diff --git a/packages/analytics/client/src/analytics_client/analytics_client.ts b/packages/analytics/ebt/client/src/analytics_client/analytics_client.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/analytics_client.ts rename to packages/analytics/ebt/client/src/analytics_client/analytics_client.ts diff --git a/packages/analytics/client/src/analytics_client/context_service.test.ts b/packages/analytics/ebt/client/src/analytics_client/context_service.test.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/context_service.test.ts rename to packages/analytics/ebt/client/src/analytics_client/context_service.test.ts diff --git a/packages/analytics/client/src/analytics_client/context_service.ts b/packages/analytics/ebt/client/src/analytics_client/context_service.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/context_service.ts rename to packages/analytics/ebt/client/src/analytics_client/context_service.ts diff --git a/packages/analytics/client/src/analytics_client/index.ts b/packages/analytics/ebt/client/src/analytics_client/index.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/index.ts rename to packages/analytics/ebt/client/src/analytics_client/index.ts diff --git a/packages/analytics/client/src/analytics_client/mocks.ts b/packages/analytics/ebt/client/src/analytics_client/mocks.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/mocks.ts rename to packages/analytics/ebt/client/src/analytics_client/mocks.ts diff --git a/packages/analytics/client/src/analytics_client/opt_in_config.test.ts b/packages/analytics/ebt/client/src/analytics_client/opt_in_config.test.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/opt_in_config.test.ts rename to packages/analytics/ebt/client/src/analytics_client/opt_in_config.test.ts diff --git a/packages/analytics/client/src/analytics_client/opt_in_config.ts b/packages/analytics/ebt/client/src/analytics_client/opt_in_config.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/opt_in_config.ts rename to packages/analytics/ebt/client/src/analytics_client/opt_in_config.ts diff --git a/packages/analytics/client/src/analytics_client/shippers_registry.test.ts b/packages/analytics/ebt/client/src/analytics_client/shippers_registry.test.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/shippers_registry.test.ts rename to packages/analytics/ebt/client/src/analytics_client/shippers_registry.test.ts diff --git a/packages/analytics/client/src/analytics_client/shippers_registry.ts b/packages/analytics/ebt/client/src/analytics_client/shippers_registry.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/shippers_registry.ts rename to packages/analytics/ebt/client/src/analytics_client/shippers_registry.ts diff --git a/packages/analytics/client/src/analytics_client/types.ts b/packages/analytics/ebt/client/src/analytics_client/types.ts similarity index 100% rename from packages/analytics/client/src/analytics_client/types.ts rename to packages/analytics/ebt/client/src/analytics_client/types.ts diff --git a/packages/analytics/client/src/events/index.ts b/packages/analytics/ebt/client/src/events/index.ts similarity index 100% rename from packages/analytics/client/src/events/index.ts rename to packages/analytics/ebt/client/src/events/index.ts diff --git a/packages/analytics/client/src/events/types.ts b/packages/analytics/ebt/client/src/events/types.ts similarity index 100% rename from packages/analytics/client/src/events/types.ts rename to packages/analytics/ebt/client/src/events/types.ts diff --git a/packages/analytics/client/src/mocks.ts b/packages/analytics/ebt/client/src/mocks.ts similarity index 100% rename from packages/analytics/client/src/mocks.ts rename to packages/analytics/ebt/client/src/mocks.ts diff --git a/packages/analytics/client/src/schema/index.ts b/packages/analytics/ebt/client/src/schema/index.ts similarity index 100% rename from packages/analytics/client/src/schema/index.ts rename to packages/analytics/ebt/client/src/schema/index.ts diff --git a/packages/analytics/client/src/schema/types.test.ts b/packages/analytics/ebt/client/src/schema/types.test.ts similarity index 100% rename from packages/analytics/client/src/schema/types.test.ts rename to packages/analytics/ebt/client/src/schema/types.test.ts diff --git a/packages/analytics/client/src/schema/types.ts b/packages/analytics/ebt/client/src/schema/types.ts similarity index 100% rename from packages/analytics/client/src/schema/types.ts rename to packages/analytics/ebt/client/src/schema/types.ts diff --git a/packages/analytics/client/src/schema/validation/excess.test.ts b/packages/analytics/ebt/client/src/schema/validation/excess.test.ts similarity index 100% rename from packages/analytics/client/src/schema/validation/excess.test.ts rename to packages/analytics/ebt/client/src/schema/validation/excess.test.ts diff --git a/packages/analytics/client/src/schema/validation/excess.ts b/packages/analytics/ebt/client/src/schema/validation/excess.ts similarity index 100% rename from packages/analytics/client/src/schema/validation/excess.ts rename to packages/analytics/ebt/client/src/schema/validation/excess.ts diff --git a/packages/analytics/client/src/schema/validation/index.ts b/packages/analytics/ebt/client/src/schema/validation/index.ts similarity index 100% rename from packages/analytics/client/src/schema/validation/index.ts rename to packages/analytics/ebt/client/src/schema/validation/index.ts diff --git a/packages/analytics/client/src/schema/validation/schema_to_io_ts.test.ts b/packages/analytics/ebt/client/src/schema/validation/schema_to_io_ts.test.ts similarity index 100% rename from packages/analytics/client/src/schema/validation/schema_to_io_ts.test.ts rename to packages/analytics/ebt/client/src/schema/validation/schema_to_io_ts.test.ts diff --git a/packages/analytics/client/src/schema/validation/schema_to_io_ts.ts b/packages/analytics/ebt/client/src/schema/validation/schema_to_io_ts.ts similarity index 100% rename from packages/analytics/client/src/schema/validation/schema_to_io_ts.ts rename to packages/analytics/ebt/client/src/schema/validation/schema_to_io_ts.ts diff --git a/packages/analytics/client/src/schema/validation/validate_schema.test.ts b/packages/analytics/ebt/client/src/schema/validation/validate_schema.test.ts similarity index 100% rename from packages/analytics/client/src/schema/validation/validate_schema.test.ts rename to packages/analytics/ebt/client/src/schema/validation/validate_schema.test.ts diff --git a/packages/analytics/client/src/schema/validation/validate_schema.ts b/packages/analytics/ebt/client/src/schema/validation/validate_schema.ts similarity index 100% rename from packages/analytics/client/src/schema/validation/validate_schema.ts rename to packages/analytics/ebt/client/src/schema/validation/validate_schema.ts diff --git a/packages/analytics/client/src/shippers/index.ts b/packages/analytics/ebt/client/src/shippers/index.ts similarity index 100% rename from packages/analytics/client/src/shippers/index.ts rename to packages/analytics/ebt/client/src/shippers/index.ts diff --git a/packages/analytics/client/src/shippers/mocks.ts b/packages/analytics/ebt/client/src/shippers/mocks.ts similarity index 100% rename from packages/analytics/client/src/shippers/mocks.ts rename to packages/analytics/ebt/client/src/shippers/mocks.ts diff --git a/packages/analytics/client/src/shippers/types.ts b/packages/analytics/ebt/client/src/shippers/types.ts similarity index 100% rename from packages/analytics/client/src/shippers/types.ts rename to packages/analytics/ebt/client/src/shippers/types.ts diff --git a/packages/analytics/ebt/index.ts b/packages/analytics/ebt/index.ts new file mode 100644 index 00000000000000..ec407b406d406c --- /dev/null +++ b/packages/analytics/ebt/index.ts @@ -0,0 +1,57 @@ +/* + * 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. + */ + +// Exporting the types here as a utility only +// The recommended way of using this library is to import from the subdirectories /client, /shippers/* +// The reason is to avoid leaking server-side code to the browser, and vice-versa +export type { + AnalyticsClient, + // Types for the constructor + AnalyticsClientInitContext, + // Types for the registerShipper API + ShipperClassConstructor, + RegisterShipperOpts, + // Types for the optIn API + OptInConfig, + OptInConfigPerType, + ShipperName, + // Types for the registerContextProvider API + ContextProviderOpts, + ContextProviderName, + // Types for the registerEventType API + EventTypeOpts, + // Events + Event, + EventContext, + EventType, + TelemetryCounter, + TelemetryCounterType, + // Schema + RootSchema, + SchemaObject, + SchemaArray, + SchemaChildValue, + SchemaMeta, + SchemaValue, + SchemaMetaOptional, + PossibleSchemaTypes, + AllowedSchemaBooleanTypes, + AllowedSchemaNumberTypes, + AllowedSchemaStringTypes, + AllowedSchemaTypes, + // Shippers + IShipper, +} from './client'; +export type { ElasticV3ShipperOptions } from './shippers/elastic_v3/common'; +export type { ElasticV3BrowserShipper } from './shippers/elastic_v3/browser'; +export type { ElasticV3ServerShipper } from './shippers/elastic_v3/server'; +export type { + FullStoryShipperConfig, + FullStoryShipper, + FullStorySnippetConfig, +} from './shippers/fullstory'; diff --git a/packages/analytics/client/jest.config.js b/packages/analytics/ebt/jest.config.js similarity index 77% rename from packages/analytics/client/jest.config.js rename to packages/analytics/ebt/jest.config.js index aa0d319f9d1e70..7296624c287b50 100644 --- a/packages/analytics/client/jest.config.js +++ b/packages/analytics/ebt/jest.config.js @@ -7,7 +7,7 @@ */ module.exports = { - preset: '@kbn/test/jest_node', - rootDir: '../../../', - roots: ['/packages/analytics/client'], + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/packages/analytics/ebt'], }; diff --git a/packages/analytics/client/kibana.jsonc b/packages/analytics/ebt/kibana.jsonc similarity index 66% rename from packages/analytics/client/kibana.jsonc rename to packages/analytics/ebt/kibana.jsonc index a027e7ee866b57..947d6224b6933f 100644 --- a/packages/analytics/client/kibana.jsonc +++ b/packages/analytics/ebt/kibana.jsonc @@ -1,5 +1,5 @@ { "type": "shared-common", - "id": "@kbn/analytics-client", + "id": "@kbn/ebt", "owner": "@elastic/kibana-core" } diff --git a/packages/analytics/client/package.json b/packages/analytics/ebt/package.json similarity index 59% rename from packages/analytics/client/package.json rename to packages/analytics/ebt/package.json index 6db911a1bac860..aee987a4c179bc 100644 --- a/packages/analytics/client/package.json +++ b/packages/analytics/ebt/package.json @@ -1,7 +1,6 @@ { - "name": "@kbn/analytics-client", + "name": "@kbn/ebt", "private": true, "version": "1.0.0", - "author": "Kibana Core", "license": "SSPL-1.0 OR Elastic License 2.0" } \ No newline at end of file diff --git a/packages/analytics/shippers/README.md b/packages/analytics/ebt/shippers/README.md similarity index 91% rename from packages/analytics/shippers/README.md rename to packages/analytics/ebt/shippers/README.md index 5ab85d08ff2ca9..3f312d1ecefe3f 100644 --- a/packages/analytics/shippers/README.md +++ b/packages/analytics/ebt/shippers/README.md @@ -1,4 +1,4 @@ -# @kbn/analytics-shippers-* +# @kbn/ebt/shippers/* This directory holds the implementation of the _built-in_ shippers provided by the Analytics client. At the moment, the shippers are: diff --git a/packages/analytics/shippers/elastic_v3/browser/README.md b/packages/analytics/ebt/shippers/elastic_v3/browser/README.md similarity index 79% rename from packages/analytics/shippers/elastic_v3/browser/README.md rename to packages/analytics/ebt/shippers/elastic_v3/browser/README.md index fcdd5e8a3ca2ee..1253a9619233d7 100644 --- a/packages/analytics/shippers/elastic_v3/browser/README.md +++ b/packages/analytics/ebt/shippers/elastic_v3/browser/README.md @@ -1,13 +1,13 @@ -# @kbn/analytics-shippers-elastic-v3-browser +# @kbn/ebt/shippers/elastic_v3/browser -UI-side implementation of the Elastic V3 shipper for the `@kbn/analytics-client`. +UI-side implementation of the Elastic V3 shipper for the `@kbn/ebt/client`. ## How to use it -This module is intended to be used **on the browser only**. Due to the nature of the UI events, they are usually more scattered in time, and we can assume a much lower load than the server. For that reason, it doesn't apply the necessary backpressure mechanisms to prevent the server from getting overloaded with too many events neither identifies if the server sits behind a firewall to discard any incoming events. Refer to `@kbn/analytics-shippers-elastic-v3-server` for the server-side implementation. +This module is intended to be used **on the browser only**. Due to the nature of the UI events, they are usually more scattered in time, and we can assume a much lower load than the server. For that reason, it doesn't apply the necessary backpressure mechanisms to prevent the server from getting overloaded with too many events neither identifies if the server sits behind a firewall to discard any incoming events. Refer to `@kbn/ebt/shippers/elastic_v3/server` for the server-side implementation. ```typescript -import { ElasticV3BrowserShipper } from "@kbn/analytics-shippers-elastic-v3-browser"; +import { ElasticV3BrowserShipper } from "@kbn/ebt/shippers/elastic_v3/browser"; analytics.registerShipper(ElasticV3BrowserShipper, { channelName: 'myChannel', version: '1.0.0' }); ``` diff --git a/packages/analytics/shippers/elastic_v3/browser/index.ts b/packages/analytics/ebt/shippers/elastic_v3/browser/index.ts similarity index 82% rename from packages/analytics/shippers/elastic_v3/browser/index.ts rename to packages/analytics/ebt/shippers/elastic_v3/browser/index.ts index 22324dc6d62180..05619fba6e6e39 100644 --- a/packages/analytics/shippers/elastic_v3/browser/index.ts +++ b/packages/analytics/ebt/shippers/elastic_v3/browser/index.ts @@ -6,5 +6,5 @@ * Side Public License, v 1. */ -export type { ElasticV3ShipperOptions } from '@kbn/analytics-shippers-elastic-v3-common'; +export type { ElasticV3ShipperOptions } from '../common'; export { ElasticV3BrowserShipper } from './src/browser_shipper'; diff --git a/packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.test.ts b/packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.test.ts similarity index 51% rename from packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.test.ts rename to packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.test.ts index dca98bddaa6ce8..fd8d7f680fd3cb 100644 --- a/packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.test.ts +++ b/packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.test.ts @@ -7,9 +7,8 @@ */ import { loggerMock } from '@kbn/logging-mocks'; -import type { AnalyticsClientInitContext, Event } from '@kbn/analytics-client'; -import { fakeSchedulers } from 'rxjs-marbles/jest'; import { firstValueFrom } from 'rxjs'; +import type { AnalyticsClientInitContext, Event } from '../../../../client'; import { ElasticV3BrowserShipper } from './browser_shipper'; describe('ElasticV3BrowserShipper', () => { @@ -33,7 +32,7 @@ describe('ElasticV3BrowserShipper', () => { let fetchMock: jest.Mock; beforeEach(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); + jest.useFakeTimers(); fetchMock = jest.fn().mockResolvedValue({ status: 200, @@ -109,37 +108,32 @@ describe('ElasticV3BrowserShipper', () => { expect(fetchMock).not.toHaveBeenCalled(); }); - test( - 'calls to reportEvents do not call `fetch` after 1s because no optIn value is set yet', - fakeSchedulers((advance) => { - shipper.reportEvents(events); - advance(1000); - expect(fetchMock).not.toHaveBeenCalled(); - }) - ); - - test( - 'calls to reportEvents call `fetch` after 1s when optIn value is set to true', - fakeSchedulers(async (advance) => { - shipper.reportEvents(events); - shipper.optIn(true); - const counter = firstValueFrom(shipper.telemetryCounter$); - advance(1000); - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - keepalive: true, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` + test('calls to reportEvents do not call `fetch` after 1s because no optIn value is set yet', async () => { + shipper.reportEvents(events); + await jest.advanceTimersByTimeAsync(1000); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + test('calls to reportEvents call `fetch` after 1s when optIn value is set to true', async () => { + shipper.reportEvents(events); + shipper.optIn(true); + const counter = firstValueFrom(shipper.telemetryCounter$); + await jest.advanceTimersByTimeAsync(1000); + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + keepalive: true, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` Object { "code": "200", "count": 1, @@ -148,43 +142,35 @@ describe('ElasticV3BrowserShipper', () => { "type": "succeeded", } `); - }) - ); - - test( - 'calls to reportEvents do not call `fetch` after 1s when optIn value is set to false', - fakeSchedulers((advance) => { - shipper.reportEvents(events); - shipper.optIn(false); - advance(1000); - expect(fetchMock).not.toHaveBeenCalled(); - }) - ); - - test( - 'calls to flush forces the client to send all the pending events', - fakeSchedulers(async (advance) => { - shipper.optIn(true); - shipper.reportEvents(events); - const counter = firstValueFrom(shipper.telemetryCounter$); - const promise = shipper.flush(); - advance(0); // bufferWhen requires some sort of fake scheduling to advance (but we are not advancing 1s) - await promise; - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - keepalive: true, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` + }); + + test('calls to reportEvents do not call `fetch` after 1s when optIn value is set to false', async () => { + shipper.reportEvents(events); + shipper.optIn(false); + await jest.advanceTimersByTimeAsync(1000); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + test('calls to flush forces the client to send all the pending events', async () => { + shipper.optIn(true); + shipper.reportEvents(events); + const counter = firstValueFrom(shipper.telemetryCounter$); + await shipper.flush(); + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + keepalive: true, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` Object { "code": "200", "count": 1, @@ -193,8 +179,7 @@ describe('ElasticV3BrowserShipper', () => { "type": "succeeded", } `); - }) - ); + }); test('calls to flush resolve immediately if there is nothing to send', async () => { shipper.optIn(true); @@ -243,55 +228,50 @@ describe('ElasticV3BrowserShipper', () => { `); }); - test( - 'does not add the query.debug: true property to the request if the shipper is not set with the debug flag', - fakeSchedulers((advance) => { - shipper = new ElasticV3BrowserShipper( - { version: '1.2.3', channelName: 'test-channel' }, - initContext - ); - shipper.reportEvents(events); - shipper.optIn(true); - advance(1000); - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - keepalive: true, - method: 'POST', - } - ); - }) - ); - - test( - 'handles when the fetch request fails', - fakeSchedulers(async (advance) => { - fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); - shipper.reportEvents(events); - shipper.optIn(true); - const counter = firstValueFrom(shipper.telemetryCounter$); - advance(1000); - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - keepalive: true, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` + test('does not add the query.debug: true property to the request if the shipper is not set with the debug flag', async () => { + shipper = new ElasticV3BrowserShipper( + { version: '1.2.3', channelName: 'test-channel' }, + initContext + ); + shipper.reportEvents(events); + shipper.optIn(true); + await jest.advanceTimersByTimeAsync(1000); + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + keepalive: true, + method: 'POST', + } + ); + }); + + test('handles when the fetch request fails', async () => { + fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); + shipper.reportEvents(events); + shipper.optIn(true); + const counter = firstValueFrom(shipper.telemetryCounter$); + await jest.advanceTimersByTimeAsync(1000); + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + keepalive: true, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` Object { "code": "Failed to fetch", "count": 1, @@ -300,36 +280,33 @@ describe('ElasticV3BrowserShipper', () => { "type": "failed", } `); - }) - ); - - test( - 'handles when the fetch request fails (request completes but not OK response)', - fakeSchedulers(async (advance) => { - fetchMock.mockResolvedValue({ - ok: false, - status: 400, - text: () => Promise.resolve('{"status": "not ok"}'), - }); - shipper.reportEvents(events); - shipper.optIn(true); - const counter = firstValueFrom(shipper.telemetryCounter$); - advance(1000); - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - keepalive: true, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` + }); + + test('handles when the fetch request fails (request completes but not OK response)', async () => { + fetchMock.mockResolvedValue({ + ok: false, + status: 400, + text: () => Promise.resolve('{"status": "not ok"}'), + }); + shipper.reportEvents(events); + shipper.optIn(true); + const counter = firstValueFrom(shipper.telemetryCounter$); + await jest.advanceTimersByTimeAsync(1000); + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + keepalive: true, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` Object { "code": "400", "count": 1, @@ -338,6 +315,5 @@ describe('ElasticV3BrowserShipper', () => { "type": "failed", } `); - }) - ); + }); }); diff --git a/packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.ts b/packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts similarity index 95% rename from packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.ts rename to packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts index 185ce37072be05..c063dcf86a95f3 100644 --- a/packages/analytics/shippers/elastic_v3/browser/src/browser_shipper.ts +++ b/packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts @@ -23,14 +23,9 @@ import type { EventContext, IShipper, TelemetryCounter, -} from '@kbn/analytics-client'; -import { ElasticV3ShipperOptions, ErrorWithCode } from '@kbn/analytics-shippers-elastic-v3-common'; -import { - buildHeaders, - buildUrl, - createTelemetryCounterHelper, - eventsToNDJSON, -} from '@kbn/analytics-shippers-elastic-v3-common'; +} from '../../../../client'; +import { ElasticV3ShipperOptions, ErrorWithCode } from '../../common'; +import { buildHeaders, buildUrl, createTelemetryCounterHelper, eventsToNDJSON } from '../../common'; /** * Elastic V3 shipper to use in the browser. diff --git a/packages/analytics/shippers/elastic_v3/common/README.md b/packages/analytics/ebt/shippers/elastic_v3/common/README.md similarity index 73% rename from packages/analytics/shippers/elastic_v3/common/README.md rename to packages/analytics/ebt/shippers/elastic_v3/common/README.md index 6684027b1ed7f3..f212c75961d861 100644 --- a/packages/analytics/shippers/elastic_v3/common/README.md +++ b/packages/analytics/ebt/shippers/elastic_v3/common/README.md @@ -1,4 +1,4 @@ -# @kbn/analytics-shippers-elastic-v3-common +# @kbn/ebt/shippers/elastic_v3/common This package holds the common code for the Elastic V3 shippers: @@ -7,4 +7,4 @@ This package holds the common code for the Elastic V3 shippers: - `eventsToNdjson` utility converts any array of events to NDJSON format. - `reportTelemetryCounters` helps with building the TelemetryCounter to emit after processing an event. -It should be considered an internal package and should not be used other than by the shipper implementations: `@kbn/analytics-shippers-elastic-v3-browser` and `@kbn/analytics-shippers-elastic-v3-server` +It should be considered an internal package and should not be used other than by the shipper implementations: `@kbn/ebt/shippers/elastic_v3/browser` and `@kbn/ebt/shippers/elastic_v3/server` diff --git a/packages/analytics/shippers/elastic_v3/common/index.ts b/packages/analytics/ebt/shippers/elastic_v3/common/index.ts similarity index 100% rename from packages/analytics/shippers/elastic_v3/common/index.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/index.ts diff --git a/packages/analytics/shippers/elastic_v3/common/src/build_headers.test.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/build_headers.test.ts similarity index 100% rename from packages/analytics/shippers/elastic_v3/common/src/build_headers.test.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/build_headers.test.ts diff --git a/packages/analytics/shippers/elastic_v3/common/src/build_headers.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/build_headers.ts similarity index 100% rename from packages/analytics/shippers/elastic_v3/common/src/build_headers.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/build_headers.ts diff --git a/packages/analytics/shippers/elastic_v3/common/src/build_url.test.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/build_url.test.ts similarity index 100% rename from packages/analytics/shippers/elastic_v3/common/src/build_url.test.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/build_url.test.ts diff --git a/packages/analytics/shippers/elastic_v3/common/src/build_url.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/build_url.ts similarity index 100% rename from packages/analytics/shippers/elastic_v3/common/src/build_url.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/build_url.ts diff --git a/packages/analytics/shippers/elastic_v3/common/src/error_with_code.test.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/error_with_code.test.ts similarity index 100% rename from packages/analytics/shippers/elastic_v3/common/src/error_with_code.test.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/error_with_code.test.ts diff --git a/packages/analytics/shippers/elastic_v3/common/src/error_with_code.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/error_with_code.ts similarity index 100% rename from packages/analytics/shippers/elastic_v3/common/src/error_with_code.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/error_with_code.ts diff --git a/packages/analytics/shippers/elastic_v3/common/src/events_to_ndjson.test.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/events_to_ndjson.test.ts similarity index 96% rename from packages/analytics/shippers/elastic_v3/common/src/events_to_ndjson.test.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/events_to_ndjson.test.ts index 4033bcb8629674..c9bcb58bb19771 100644 --- a/packages/analytics/shippers/elastic_v3/common/src/events_to_ndjson.test.ts +++ b/packages/analytics/ebt/shippers/elastic_v3/common/src/events_to_ndjson.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { Event } from '@kbn/analytics-client'; +import type { Event } from '../../../../client'; import { eventsToNDJSON } from './events_to_ndjson'; describe('eventsToNDJSON', () => { diff --git a/packages/analytics/shippers/elastic_v3/common/src/events_to_ndjson.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/events_to_ndjson.ts similarity index 92% rename from packages/analytics/shippers/elastic_v3/common/src/events_to_ndjson.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/events_to_ndjson.ts index f5dc22ff841173..bfd5aabc1223a3 100644 --- a/packages/analytics/shippers/elastic_v3/common/src/events_to_ndjson.ts +++ b/packages/analytics/ebt/shippers/elastic_v3/common/src/events_to_ndjson.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { Event } from '@kbn/analytics-client'; +import type { Event } from '../../../../client'; /** * Converts an array of events to a single ndjson string. diff --git a/packages/analytics/shippers/elastic_v3/common/src/report_telemetry_counters.test.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/report_telemetry_counters.test.ts similarity index 98% rename from packages/analytics/shippers/elastic_v3/common/src/report_telemetry_counters.test.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/report_telemetry_counters.test.ts index 33cba78f8b2975..a720a0c0129a61 100644 --- a/packages/analytics/shippers/elastic_v3/common/src/report_telemetry_counters.test.ts +++ b/packages/analytics/ebt/shippers/elastic_v3/common/src/report_telemetry_counters.test.ts @@ -7,7 +7,7 @@ */ import { firstValueFrom, Subject, take, toArray } from 'rxjs'; -import type { Event, TelemetryCounter } from '@kbn/analytics-client'; +import type { Event, TelemetryCounter } from '../../../../client'; import { createTelemetryCounterHelper } from './report_telemetry_counters'; describe('reportTelemetryCounters', () => { diff --git a/packages/analytics/shippers/elastic_v3/common/src/report_telemetry_counters.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/report_telemetry_counters.ts similarity index 98% rename from packages/analytics/shippers/elastic_v3/common/src/report_telemetry_counters.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/report_telemetry_counters.ts index 36deae1732f7a4..68260e653e78db 100644 --- a/packages/analytics/shippers/elastic_v3/common/src/report_telemetry_counters.ts +++ b/packages/analytics/ebt/shippers/elastic_v3/common/src/report_telemetry_counters.ts @@ -7,7 +7,7 @@ */ import type { Subject } from 'rxjs'; -import type { Event, TelemetryCounter, TelemetryCounterType } from '@kbn/analytics-client'; +import type { Event, TelemetryCounter, TelemetryCounterType } from '../../../../client'; /** * Creates a telemetry counter helper to make it easier to generate them diff --git a/packages/analytics/shippers/elastic_v3/common/src/types.ts b/packages/analytics/ebt/shippers/elastic_v3/common/src/types.ts similarity index 100% rename from packages/analytics/shippers/elastic_v3/common/src/types.ts rename to packages/analytics/ebt/shippers/elastic_v3/common/src/types.ts diff --git a/packages/analytics/shippers/elastic_v3/server/README.md b/packages/analytics/ebt/shippers/elastic_v3/server/README.md similarity index 83% rename from packages/analytics/shippers/elastic_v3/server/README.md rename to packages/analytics/ebt/shippers/elastic_v3/server/README.md index edb4bdffa0dbae..0c27cef5a00233 100644 --- a/packages/analytics/shippers/elastic_v3/server/README.md +++ b/packages/analytics/ebt/shippers/elastic_v3/server/README.md @@ -1,13 +1,13 @@ -# @kbn/analytics-shippers-elastic-v3-server +# @kbn/ebt/shippers/elastic_v3/server -Server-side implementation of the Elastic V3 shipper for the `@kbn/analytics-client`. +Server-side implementation of the Elastic V3 shipper for the `@kbn/ebt/client`. ## How to use it -This module is intended to be used **on the server-side only**. It is specially designed to apply the necessary backpressure mechanisms to prevent the server from getting overloaded with too many events and identify if the server sits behind a firewall to discard any incoming events. Refer to `@kbn/analytics-shippers-elastic-v3-browser` for the browser-side implementation. +This module is intended to be used **on the server-side only**. It is specially designed to apply the necessary backpressure mechanisms to prevent the server from getting overloaded with too many events and identify if the server sits behind a firewall to discard any incoming events. Refer to `@kbn/ebt/shippers/elastic_v3/browser` for the browser-side implementation. ```typescript -import { ElasticV3ServerShipper } from "@kbn/analytics-shippers-elastic-v3-server"; +import { ElasticV3ServerShipper } from "@kbn/ebt/shippers/elastic_v3/server"; analytics.registerShipper(ElasticV3ServerShipper, { channelName: 'myChannel', version: '1.0.0' }); ``` diff --git a/packages/analytics/shippers/elastic_v3/server/index.ts b/packages/analytics/ebt/shippers/elastic_v3/server/index.ts similarity index 82% rename from packages/analytics/shippers/elastic_v3/server/index.ts rename to packages/analytics/ebt/shippers/elastic_v3/server/index.ts index d5d0cb04a21ed3..c0031aac4b2179 100644 --- a/packages/analytics/shippers/elastic_v3/server/index.ts +++ b/packages/analytics/ebt/shippers/elastic_v3/server/index.ts @@ -6,5 +6,5 @@ * Side Public License, v 1. */ -export type { ElasticV3ShipperOptions } from '@kbn/analytics-shippers-elastic-v3-common'; +export type { ElasticV3ShipperOptions } from '../common'; export { ElasticV3ServerShipper } from './src/server_shipper'; diff --git a/packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.mocks.ts b/packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.test.mocks.ts similarity index 100% rename from packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.mocks.ts rename to packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.test.mocks.ts diff --git a/packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.test.ts b/packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.test.ts new file mode 100644 index 00000000000000..1e973ed4c98199 --- /dev/null +++ b/packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.test.ts @@ -0,0 +1,571 @@ +/* + * 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 { loggerMock } from '@kbn/logging-mocks'; +import { firstValueFrom } from 'rxjs'; +import type { AnalyticsClientInitContext, Event } from '../../../../client'; +import { fetchMock } from './server_shipper.test.mocks'; +import { ElasticV3ServerShipper } from './server_shipper'; + +const SECONDS = 1000; +const MINUTES = 60 * SECONDS; + +describe('ElasticV3ServerShipper', () => { + const events: Event[] = [ + { + timestamp: '2020-01-01T00:00:00.000Z', + event_type: 'test-event-type', + context: {}, + properties: {}, + }, + ]; + + const initContext: AnalyticsClientInitContext = { + sendTo: 'staging', + isDev: true, + logger: loggerMock.create(), + }; + + let shipper: ElasticV3ServerShipper; + + // eslint-disable-next-line dot-notation + const setLastBatchSent = (ms: number) => (shipper['lastBatchSent'] = ms); + + beforeEach(() => { + jest.useFakeTimers({ legacyFakeTimers: false }); + + shipper = new ElasticV3ServerShipper( + { version: '1.2.3', channelName: 'test-channel', debug: true }, + initContext + ); + // eslint-disable-next-line dot-notation + shipper['firstTimeOffline'] = null; // The tests think connectivity is OK initially for easier testing. + }); + + afterEach(() => { + shipper.shutdown(); + jest.clearAllMocks(); + }); + + test('set optIn should update the isOptedIn$ observable', () => { + // eslint-disable-next-line dot-notation + const getInternalOptIn = () => shipper['isOptedIn$'].value; + + // Initially undefined + expect(getInternalOptIn()).toBeUndefined(); + + shipper.optIn(true); + expect(getInternalOptIn()).toBe(true); + + shipper.optIn(false); + expect(getInternalOptIn()).toBe(false); + }); + + test('clears the queue after optIn: false', () => { + shipper.reportEvents(events); + // eslint-disable-next-line dot-notation + expect(shipper['internalQueue'].length).toBe(1); + + shipper.optIn(false); + // eslint-disable-next-line dot-notation + expect(shipper['internalQueue'].length).toBe(0); + }); + + test('set extendContext should store local values: clusterUuid and licenseId', () => { + // eslint-disable-next-line dot-notation + const getInternalClusterUuid = () => shipper['clusterUuid']; + // eslint-disable-next-line dot-notation + const getInternalLicenseId = () => shipper['licenseId']; + + // Initial values + expect(getInternalClusterUuid()).toBe('UNKNOWN'); + expect(getInternalLicenseId()).toBeUndefined(); + + shipper.extendContext({ cluster_uuid: 'test-cluster-uuid' }); + expect(getInternalClusterUuid()).toBe('test-cluster-uuid'); + expect(getInternalLicenseId()).toBeUndefined(); + + shipper.extendContext({ license_id: 'test-license-id' }); + expect(getInternalClusterUuid()).toBe('test-cluster-uuid'); + expect(getInternalLicenseId()).toBe('test-license-id'); + + shipper.extendContext({ cluster_uuid: 'test-cluster-uuid-2', license_id: 'test-license-id-2' }); + expect(getInternalClusterUuid()).toBe('test-cluster-uuid-2'); + expect(getInternalLicenseId()).toBe('test-license-id-2'); + }); + + test('calls to reportEvents do not call `fetch` straight away', () => { + shipper.reportEvents(events); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + test('calls to reportEvents do not call `fetch` after 10 minutes because no optIn value is set yet', async () => { + shipper.reportEvents(events); + await jest.advanceTimersByTimeAsync(10 * MINUTES); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + test('calls to reportEvents call `fetch` after 10 seconds when optIn value is set to true', async () => { + shipper.reportEvents(events); + shipper.optIn(true); + const counter = firstValueFrom(shipper.telemetryCounter$); + setLastBatchSent(Date.now() - 10 * SECONDS); + await jest.advanceTimersByTimeAsync(1 * SECONDS); // Moving 1 second should be enough to trigger the logic + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` + Object { + "code": "200", + "count": 1, + "event_type": "test-event-type", + "source": "elastic_v3_server", + "type": "succeeded", + } + `); + }); + + test('calls to reportEvents do not call `fetch` after 10 seconds when optIn value is set to false', async () => { + shipper.reportEvents(events); + shipper.optIn(false); + setLastBatchSent(Date.now() - 10 * SECONDS); + await jest.advanceTimersByTimeAsync(1 * SECONDS); // Moving 1 second should be enough to trigger the logic + expect(fetchMock).not.toHaveBeenCalled(); + }); + + test('calls to reportEvents call `fetch` when shutting down if optIn value is set to true', async () => { + shipper.reportEvents(events); + shipper.optIn(true); + const counter = firstValueFrom(shipper.telemetryCounter$); + shipper.shutdown(); + jest.advanceTimersToNextTimer(); // We are handling the shutdown in a promise, so we need to wait for the next tick. + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` + Object { + "code": "200", + "count": 1, + "event_type": "test-event-type", + "source": "elastic_v3_server", + "type": "succeeded", + } + `); + }); + + test('does not add the query.debug: true property to the request if the shipper is not set with the debug flag', async () => { + shipper = new ElasticV3ServerShipper( + { version: '1.2.3', channelName: 'test-channel' }, + initContext + ); + // eslint-disable-next-line dot-notation + shipper['firstTimeOffline'] = null; + shipper.reportEvents(events); + shipper.optIn(true); + setLastBatchSent(Date.now() - 10 * SECONDS); + await jest.advanceTimersByTimeAsync(1 * SECONDS); // Moving 1 second should be enough to trigger the logic + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + method: 'POST', + } + ); + }); + + test('sends when the queue overflows the 10kB leaky bucket one batch every 10s', async () => { + expect.assertions(2 * 9 + 2); + + shipper.reportEvents(new Array(1000).fill(events[0])); + shipper.optIn(true); + + // Due to the size of the test events, it matches 8 rounds. + for (let i = 0; i < 9; i++) { + const counter = firstValueFrom(shipper.telemetryCounter$); + setLastBatchSent(Date.now() - 10 * SECONDS); + await jest.advanceTimersByTimeAsync(1 * SECONDS); // Moving 1 second should be enough to trigger the logic + expect(fetchMock).toHaveBeenNthCalledWith( + i + 1, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: new Array(103) + .fill( + '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n' + ) + .join(''), + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` + Object { + "code": "200", + "count": 103, + "event_type": "test-event-type", + "source": "elastic_v3_server", + "type": "succeeded", + } + `); + jest.advanceTimersToNextTimer(); + } + // eslint-disable-next-line dot-notation + expect(shipper['internalQueue'].length).toBe(1000 - 9 * 103); // 73 + + // If we call it again, it should not enqueue all the events (only the ones to fill the queue): + shipper.reportEvents(new Array(1000).fill(events[0])); + // eslint-disable-next-line dot-notation + expect(shipper['internalQueue'].length).toBe(1000); + }); + + test('handles when the fetch request fails', async () => { + fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); + shipper.reportEvents(events); + shipper.optIn(true); + const counter = firstValueFrom(shipper.telemetryCounter$); + setLastBatchSent(Date.now() - 10 * SECONDS); + await jest.advanceTimersByTimeAsync(1 * SECONDS); // Moving 1 second should be enough to trigger the logic + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` + Object { + "code": "Failed to fetch", + "count": 1, + "event_type": "test-event-type", + "source": "elastic_v3_server", + "type": "failed", + } + `); + }); + + test('handles when the fetch request fails (request completes but not OK response)', async () => { + fetchMock.mockResolvedValueOnce({ + ok: false, + status: 400, + text: () => Promise.resolve('{"status": "not ok"}'), + }); + shipper.reportEvents(events); + shipper.optIn(true); + const counter = firstValueFrom(shipper.telemetryCounter$); + setLastBatchSent(Date.now() - 10 * SECONDS); + await jest.advanceTimersByTimeAsync(1 * SECONDS); // Moving 1 second should be enough to trigger the logic + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` + Object { + "code": "400", + "count": 1, + "event_type": "test-event-type", + "source": "elastic_v3_server", + "type": "failed", + } + `); + }); + + describe('Connectivity Checks', () => { + describe('connectivity check when connectivity is confirmed (firstTimeOffline === null)', () => { + test.each([undefined, false, true])('does not run for opt-in %p', async (optInValue) => { + if (optInValue !== undefined) { + shipper.optIn(optInValue); + } + + // From the start, it doesn't check connectivity because already confirmed + expect(fetchMock).not.toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + + // Wait a big time (1 minute should be enough, but for the sake of tests...) + await jest.advanceTimersByTimeAsync(10 * MINUTES); + + expect(fetchMock).not.toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + }); + }); + + describe('connectivity check with initial unknown state of the connectivity', () => { + beforeEach(() => { + // eslint-disable-next-line dot-notation + shipper['firstTimeOffline'] = undefined; // Initial unknown state of the connectivity + }); + + test.each([undefined, false])('does not run for opt-in %p', async (optInValue) => { + if (optInValue !== undefined) { + shipper.optIn(optInValue); + } + + // From the start, it doesn't check connectivity because already confirmed + expect(fetchMock).not.toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + + // Wait a big time (1 minute should be enough, but for the sake of tests...) + await jest.advanceTimersByTimeAsync(10 * MINUTES); + + expect(fetchMock).not.toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + }); + + test('runs as soon as opt-in is set to true', () => { + shipper.optIn(true); + + // From the start, it doesn't check connectivity because opt-in is not true + expect(fetchMock).toHaveBeenNthCalledWith( + 1, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + }); + }); + + describe('connectivity check with the connectivity confirmed to be faulty', () => { + beforeEach(() => { + // eslint-disable-next-line dot-notation + shipper['firstTimeOffline'] = 100; // Failed at some point + }); + + test.each([undefined, false])('does not run for opt-in %p', async (optInValue) => { + if (optInValue !== undefined) { + shipper.optIn(optInValue); + } + + // From the start, it doesn't check connectivity because already confirmed + expect(fetchMock).not.toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + + // Wait a big time (1 minute should be enough, but for the sake of tests...) + await jest.advanceTimersByTimeAsync(10 * MINUTES); + + expect(fetchMock).not.toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + }); + + test('runs as soon as opt-in is set to true', () => { + shipper.optIn(true); + + // From the start, it doesn't check connectivity because opt-in is not true + expect(fetchMock).toHaveBeenNthCalledWith( + 1, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + }); + }); + + describe('after report failure', () => { + // generate the report failure for each test + beforeEach(async () => { + fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); + shipper.reportEvents(events); + shipper.optIn(true); + const counter = firstValueFrom(shipper.telemetryCounter$); + setLastBatchSent(Date.now() - 10 * SECONDS); + await jest.advanceTimersByTimeAsync(1 * SECONDS); // Moving 1 second should be enough to trigger the logic + expect(fetchMock).toHaveBeenNthCalledWith( + 1, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + method: 'POST', + query: { debug: true }, + } + ); + await expect(counter).resolves.toMatchInlineSnapshot(` + Object { + "code": "Failed to fetch", + "count": 1, + "event_type": "test-event-type", + "source": "elastic_v3_server", + "type": "failed", + } + `); + }); + + test('connectivity check runs periodically', async () => { + fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); + await jest.advanceTimersByTimeAsync(1 * MINUTES); + expect(fetchMock).toHaveBeenNthCalledWith( + 2, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + fetchMock.mockResolvedValueOnce({ ok: false }); + await jest.advanceTimersByTimeAsync(2 * MINUTES); + expect(fetchMock).toHaveBeenNthCalledWith( + 3, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + }); + }); + + describe('after being offline for longer than 24h', () => { + beforeEach(() => { + shipper.optIn(true); + shipper.reportEvents(events); + // eslint-disable-next-line dot-notation + expect(shipper['internalQueue'].length).toBe(1); + // eslint-disable-next-line dot-notation + shipper['firstTimeOffline'] = 100; + }); + + test('the following connectivity check clears the queue', async () => { + fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); + await jest.advanceTimersByTimeAsync(1 * MINUTES); + expect(fetchMock).toHaveBeenNthCalledWith( + 1, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + // eslint-disable-next-line dot-notation + expect(shipper['internalQueue'].length).toBe(0); + }); + + test('new events are not added to the queue', async () => { + fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); + await jest.advanceTimersByTimeAsync(1 * MINUTES); + expect(fetchMock).toHaveBeenNthCalledWith( + 1, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + // eslint-disable-next-line dot-notation + expect(shipper['internalQueue'].length).toBe(0); + + shipper.reportEvents(events); + // eslint-disable-next-line dot-notation + expect(shipper['internalQueue'].length).toBe(0); + }); + + test('regains the connection', async () => { + fetchMock.mockResolvedValueOnce({ ok: true }); + await jest.advanceTimersByTimeAsync(1 * MINUTES); + expect(fetchMock).toHaveBeenNthCalledWith( + 1, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + // eslint-disable-next-line dot-notation + expect(shipper['firstTimeOffline']).toBe(null); + + await jest.advanceTimersByTimeAsync(10 * MINUTES); + expect(fetchMock).not.toHaveBeenNthCalledWith( + 2, + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { method: 'OPTIONS' } + ); + }); + }); + }); + + describe('flush method', () => { + test('resolves straight away if it should not send anything', async () => { + await expect(shipper.flush()).resolves.toBe(undefined); + }); + + test('resolves when all the ongoing requests are complete', async () => { + shipper.optIn(true); + shipper.reportEvents(events); + expect(fetchMock).toHaveBeenCalledTimes(0); + fetchMock.mockImplementation(async () => { + // eslint-disable-next-line dot-notation + expect(shipper['inFlightRequests$'].value).toBe(1); + }); + await expect(shipper.flush()).resolves.toBe(undefined); + expect(fetchMock).toHaveBeenCalledWith( + 'https://telemetry-staging.elastic.co/v3/send/test-channel', + { + body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', + headers: { + 'content-type': 'application/x-ndjson', + 'x-elastic-cluster-id': 'UNKNOWN', + 'x-elastic-stack-version': '1.2.3', + }, + method: 'POST', + query: { debug: true }, + } + ); + }); + + test('calling flush multiple times does not keep hanging', async () => { + await expect(shipper.flush()).resolves.toBe(undefined); + await expect(shipper.flush()).resolves.toBe(undefined); + await Promise.all([shipper.flush(), shipper.flush()]); + }); + + test('calling flush after shutdown does not keep hanging', async () => { + shipper.shutdown(); + await expect(shipper.flush()).resolves.toBe(undefined); + }); + }); +}); diff --git a/packages/analytics/shippers/elastic_v3/server/src/server_shipper.ts b/packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts similarity index 99% rename from packages/analytics/shippers/elastic_v3/server/src/server_shipper.ts rename to packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts index cb6e689dd893ff..d3b54da3314cf3 100644 --- a/packages/analytics/shippers/elastic_v3/server/src/server_shipper.ts +++ b/packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts @@ -25,13 +25,6 @@ import { skip, firstValueFrom, } from 'rxjs'; -import type { - AnalyticsClientInitContext, - Event, - EventContext, - IShipper, - TelemetryCounter, -} from '@kbn/analytics-client'; import { type ElasticV3ShipperOptions, buildHeaders, @@ -39,7 +32,14 @@ import { createTelemetryCounterHelper, eventsToNDJSON, ErrorWithCode, -} from '@kbn/analytics-shippers-elastic-v3-common'; +} from '../../common'; +import type { + AnalyticsClientInitContext, + Event, + EventContext, + IShipper, + TelemetryCounter, +} from '../../../../client'; const SECOND = 1000; const MINUTE = 60 * SECOND; diff --git a/packages/analytics/shippers/fullstory/README.md b/packages/analytics/ebt/shippers/fullstory/README.md similarity index 91% rename from packages/analytics/shippers/fullstory/README.md rename to packages/analytics/ebt/shippers/fullstory/README.md index 6d1c443db3d228..a1e557a7600b8f 100644 --- a/packages/analytics/shippers/fullstory/README.md +++ b/packages/analytics/ebt/shippers/fullstory/README.md @@ -1,13 +1,13 @@ -# @kbn/analytics-shippers-fullstory +# @kbn/ebt/shippers/fullstory -FullStory implementation as a shipper for the `@kbn/analytics-client`. +FullStory implementation as a shipper for the `@kbn/ebt/client`. ## How to use it This module is intended to be used **on the browser only**. It does not support server-side events. ```typescript -import { FullStoryShipper } from "@kbn/analytics-shippers-fullstory"; +import { FullStoryShipper } from "@kbn/ebt/shippers/fullstory"; analytics.registerShipper(FullStoryShipper, { fullStoryOrgId: '12345' }) ``` diff --git a/packages/analytics/shippers/fullstory/index.ts b/packages/analytics/ebt/shippers/fullstory/index.ts similarity index 100% rename from packages/analytics/shippers/fullstory/index.ts rename to packages/analytics/ebt/shippers/fullstory/index.ts diff --git a/packages/analytics/shippers/fullstory/src/format_payload.test.ts b/packages/analytics/ebt/shippers/fullstory/src/format_payload.test.ts similarity index 100% rename from packages/analytics/shippers/fullstory/src/format_payload.test.ts rename to packages/analytics/ebt/shippers/fullstory/src/format_payload.test.ts diff --git a/packages/analytics/shippers/fullstory/src/format_payload.ts b/packages/analytics/ebt/shippers/fullstory/src/format_payload.ts similarity index 100% rename from packages/analytics/shippers/fullstory/src/format_payload.ts rename to packages/analytics/ebt/shippers/fullstory/src/format_payload.ts diff --git a/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.mocks.ts b/packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.test.mocks.ts similarity index 100% rename from packages/analytics/shippers/fullstory/src/fullstory_shipper.test.mocks.ts rename to packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.test.mocks.ts diff --git a/packages/analytics/shippers/fullstory/src/fullstory_shipper.test.ts b/packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.test.ts similarity index 100% rename from packages/analytics/shippers/fullstory/src/fullstory_shipper.test.ts rename to packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.test.ts diff --git a/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts b/packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts similarity index 96% rename from packages/analytics/shippers/fullstory/src/fullstory_shipper.ts rename to packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts index 96ae3389be0173..a091076236a80e 100644 --- a/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts +++ b/packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts @@ -6,15 +6,10 @@ * Side Public License, v 1. */ -import type { - AnalyticsClientInitContext, - EventContext, - Event, - IShipper, -} from '@kbn/analytics-client'; import { Subject, distinct, debounceTime, map, filter, Subscription } from 'rxjs'; import { get, has } from 'lodash'; import { set } from '@kbn/safer-lodash-set'; +import type { AnalyticsClientInitContext, EventContext, Event, IShipper } from '../../../client'; import type { FullStoryApi } from './types'; import type { FullStorySnippetConfig } from './load_snippet'; import { formatPayload } from './format_payload'; @@ -56,6 +51,10 @@ export interface FullStoryShipperConfig extends FullStorySnippetConfig { * If this setting is provided, it'll only send the event types specified in this list. */ eventTypesAllowlist?: string[]; + /** + * FullStory only allows calling setVars('page') once per navigation. + * This setting defines how much time to hold from calling the API while additional lazy context is being resolved. + */ pageVarsDebounceTimeMs?: number; } diff --git a/packages/analytics/shippers/fullstory/src/get_parsed_version.test.ts b/packages/analytics/ebt/shippers/fullstory/src/get_parsed_version.test.ts similarity index 100% rename from packages/analytics/shippers/fullstory/src/get_parsed_version.test.ts rename to packages/analytics/ebt/shippers/fullstory/src/get_parsed_version.test.ts diff --git a/packages/analytics/shippers/fullstory/src/get_parsed_version.ts b/packages/analytics/ebt/shippers/fullstory/src/get_parsed_version.ts similarity index 100% rename from packages/analytics/shippers/fullstory/src/get_parsed_version.ts rename to packages/analytics/ebt/shippers/fullstory/src/get_parsed_version.ts diff --git a/packages/analytics/shippers/fullstory/src/load_snippet.test.ts b/packages/analytics/ebt/shippers/fullstory/src/load_snippet.test.ts similarity index 68% rename from packages/analytics/shippers/fullstory/src/load_snippet.test.ts rename to packages/analytics/ebt/shippers/fullstory/src/load_snippet.test.ts index 0b920ef2d22c12..002f113f71f63b 100644 --- a/packages/analytics/shippers/fullstory/src/load_snippet.test.ts +++ b/packages/analytics/ebt/shippers/fullstory/src/load_snippet.test.ts @@ -11,25 +11,11 @@ import { loadSnippet } from './load_snippet'; describe('loadSnippet', () => { beforeAll(() => { // Define necessary window and document global variables for the tests - Object.defineProperty(global, 'window', { - writable: true, - value: {}, - }); - - Object.defineProperty(global, 'document', { - writable: true, - value: { - createElement: jest.fn().mockReturnValue({}), - getElementsByTagName: jest - .fn() - .mockReturnValue([{ parentNode: { insertBefore: jest.fn() } }]), - }, - }); - - Object.defineProperty(global, '_fs_script', { - writable: true, - value: '', - }); + jest + .spyOn(global.document, 'getElementsByTagName') + .mockReturnValue([ + { parentNode: { insertBefore: jest.fn() } }, + ] as unknown as HTMLCollectionOf); }); it('should return the FullStory API', () => { diff --git a/packages/analytics/shippers/fullstory/src/load_snippet.ts b/packages/analytics/ebt/shippers/fullstory/src/load_snippet.ts similarity index 100% rename from packages/analytics/shippers/fullstory/src/load_snippet.ts rename to packages/analytics/ebt/shippers/fullstory/src/load_snippet.ts diff --git a/packages/analytics/shippers/fullstory/src/types.ts b/packages/analytics/ebt/shippers/fullstory/src/types.ts similarity index 100% rename from packages/analytics/shippers/fullstory/src/types.ts rename to packages/analytics/ebt/shippers/fullstory/src/types.ts diff --git a/packages/analytics/client/tsconfig.json b/packages/analytics/ebt/tsconfig.json similarity index 63% rename from packages/analytics/client/tsconfig.json rename to packages/analytics/ebt/tsconfig.json index b5bb1c1f7c0106..38e6caee5d2a1a 100644 --- a/packages/analytics/client/tsconfig.json +++ b/packages/analytics/ebt/tsconfig.json @@ -4,17 +4,20 @@ "outDir": "target/types", "types": [ "jest", - "node" + "node", + "react" ] }, "include": [ - "**/*.ts" + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" ], "kbn_references": [ + "@kbn/logging-mocks", "@kbn/logging", - "@kbn/logging-mocks" - ], - "exclude": [ - "target/**/*", + "@kbn/safer-lodash-set", ] } diff --git a/packages/analytics/shippers/elastic_v3/browser/jest.config.js b/packages/analytics/shippers/elastic_v3/browser/jest.config.js deleted file mode 100644 index 20067863aad978..00000000000000 --- a/packages/analytics/shippers/elastic_v3/browser/jest.config.js +++ /dev/null @@ -1,13 +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. - */ - -module.exports = { - preset: '@kbn/test/jest_node', - rootDir: '../../../../../', - roots: ['/packages/analytics/shippers/elastic_v3/browser'], -}; diff --git a/packages/analytics/shippers/elastic_v3/browser/kibana.jsonc b/packages/analytics/shippers/elastic_v3/browser/kibana.jsonc deleted file mode 100644 index a54bd23df252dd..00000000000000 --- a/packages/analytics/shippers/elastic_v3/browser/kibana.jsonc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "shared-common", - "id": "@kbn/analytics-shippers-elastic-v3-browser", - "owner": "@elastic/kibana-core" -} diff --git a/packages/analytics/shippers/elastic_v3/browser/package.json b/packages/analytics/shippers/elastic_v3/browser/package.json deleted file mode 100644 index 88d42d1fd184be..00000000000000 --- a/packages/analytics/shippers/elastic_v3/browser/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/analytics-shippers-elastic-v3-browser", - "private": true, - "version": "1.0.0", - "author": "Kibana Core", - "license": "SSPL-1.0 OR Elastic License 2.0" -} \ No newline at end of file diff --git a/packages/analytics/shippers/elastic_v3/browser/tsconfig.json b/packages/analytics/shippers/elastic_v3/browser/tsconfig.json deleted file mode 100644 index 7808dee7058f00..00000000000000 --- a/packages/analytics/shippers/elastic_v3/browser/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "../../../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/analytics-client", - "@kbn/analytics-shippers-elastic-v3-common", - "@kbn/logging-mocks" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/analytics/shippers/elastic_v3/common/jest.config.js b/packages/analytics/shippers/elastic_v3/common/jest.config.js deleted file mode 100644 index 1336211347fb7d..00000000000000 --- a/packages/analytics/shippers/elastic_v3/common/jest.config.js +++ /dev/null @@ -1,13 +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. - */ - -module.exports = { - preset: '@kbn/test/jest_node', - rootDir: '../../../../../', - roots: ['/packages/analytics/shippers/elastic_v3/common'], -}; diff --git a/packages/analytics/shippers/elastic_v3/common/kibana.jsonc b/packages/analytics/shippers/elastic_v3/common/kibana.jsonc deleted file mode 100644 index 30c723c2b52178..00000000000000 --- a/packages/analytics/shippers/elastic_v3/common/kibana.jsonc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "shared-common", - "id": "@kbn/analytics-shippers-elastic-v3-common", - "owner": "@elastic/kibana-core" -} diff --git a/packages/analytics/shippers/elastic_v3/common/package.json b/packages/analytics/shippers/elastic_v3/common/package.json deleted file mode 100644 index 4e1caaf0d6a2f7..00000000000000 --- a/packages/analytics/shippers/elastic_v3/common/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/analytics-shippers-elastic-v3-common", - "private": true, - "version": "1.0.0", - "author": "Kibana Core", - "license": "SSPL-1.0 OR Elastic License 2.0" -} \ No newline at end of file diff --git a/packages/analytics/shippers/elastic_v3/common/tsconfig.json b/packages/analytics/shippers/elastic_v3/common/tsconfig.json deleted file mode 100644 index 698191a0c3816d..00000000000000 --- a/packages/analytics/shippers/elastic_v3/common/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../../../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/analytics-client" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/analytics/shippers/elastic_v3/server/jest.config.js b/packages/analytics/shippers/elastic_v3/server/jest.config.js deleted file mode 100644 index 4397eb3e50c5ae..00000000000000 --- a/packages/analytics/shippers/elastic_v3/server/jest.config.js +++ /dev/null @@ -1,13 +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. - */ - -module.exports = { - preset: '@kbn/test/jest_node', - rootDir: '../../../../../', - roots: ['/packages/analytics/shippers/elastic_v3/server'], -}; diff --git a/packages/analytics/shippers/elastic_v3/server/kibana.jsonc b/packages/analytics/shippers/elastic_v3/server/kibana.jsonc deleted file mode 100644 index a516db1bbf30ec..00000000000000 --- a/packages/analytics/shippers/elastic_v3/server/kibana.jsonc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "shared-common", - "id": "@kbn/analytics-shippers-elastic-v3-server", - "owner": "@elastic/kibana-core" -} diff --git a/packages/analytics/shippers/elastic_v3/server/package.json b/packages/analytics/shippers/elastic_v3/server/package.json deleted file mode 100644 index 3fcbd5062d35fd..00000000000000 --- a/packages/analytics/shippers/elastic_v3/server/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/analytics-shippers-elastic-v3-server", - "private": true, - "version": "1.0.0", - "author": "Kibana Core", - "license": "SSPL-1.0 OR Elastic License 2.0" -} \ No newline at end of file diff --git a/packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.ts b/packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.ts deleted file mode 100644 index 1d5ab760d15f28..00000000000000 --- a/packages/analytics/shippers/elastic_v3/server/src/server_shipper.test.ts +++ /dev/null @@ -1,624 +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 { loggerMock } from '@kbn/logging-mocks'; -import { firstValueFrom } from 'rxjs'; -import { fakeSchedulers } from 'rxjs-marbles/jest'; -import type { AnalyticsClientInitContext, Event } from '@kbn/analytics-client'; -import { fetchMock } from './server_shipper.test.mocks'; -import { ElasticV3ServerShipper } from './server_shipper'; - -const SECONDS = 1000; -const MINUTES = 60 * SECONDS; - -describe('ElasticV3ServerShipper', () => { - const events: Event[] = [ - { - timestamp: '2020-01-01T00:00:00.000Z', - event_type: 'test-event-type', - context: {}, - properties: {}, - }, - ]; - - const nextTick = () => new Promise((resolve) => setImmediate(resolve)); - - const initContext: AnalyticsClientInitContext = { - sendTo: 'staging', - isDev: true, - logger: loggerMock.create(), - }; - - let shipper: ElasticV3ServerShipper; - - // eslint-disable-next-line dot-notation - const setLastBatchSent = (ms: number) => (shipper['lastBatchSent'] = ms); - - beforeEach(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); - - shipper = new ElasticV3ServerShipper( - { version: '1.2.3', channelName: 'test-channel', debug: true }, - initContext - ); - // eslint-disable-next-line dot-notation - shipper['firstTimeOffline'] = null; // The tests think connectivity is OK initially for easier testing. - }); - - afterEach(() => { - shipper.shutdown(); - jest.clearAllMocks(); - }); - - test('set optIn should update the isOptedIn$ observable', () => { - // eslint-disable-next-line dot-notation - const getInternalOptIn = () => shipper['isOptedIn$'].value; - - // Initially undefined - expect(getInternalOptIn()).toBeUndefined(); - - shipper.optIn(true); - expect(getInternalOptIn()).toBe(true); - - shipper.optIn(false); - expect(getInternalOptIn()).toBe(false); - }); - - test('clears the queue after optIn: false', () => { - shipper.reportEvents(events); - // eslint-disable-next-line dot-notation - expect(shipper['internalQueue'].length).toBe(1); - - shipper.optIn(false); - // eslint-disable-next-line dot-notation - expect(shipper['internalQueue'].length).toBe(0); - }); - - test('set extendContext should store local values: clusterUuid and licenseId', () => { - // eslint-disable-next-line dot-notation - const getInternalClusterUuid = () => shipper['clusterUuid']; - // eslint-disable-next-line dot-notation - const getInternalLicenseId = () => shipper['licenseId']; - - // Initial values - expect(getInternalClusterUuid()).toBe('UNKNOWN'); - expect(getInternalLicenseId()).toBeUndefined(); - - shipper.extendContext({ cluster_uuid: 'test-cluster-uuid' }); - expect(getInternalClusterUuid()).toBe('test-cluster-uuid'); - expect(getInternalLicenseId()).toBeUndefined(); - - shipper.extendContext({ license_id: 'test-license-id' }); - expect(getInternalClusterUuid()).toBe('test-cluster-uuid'); - expect(getInternalLicenseId()).toBe('test-license-id'); - - shipper.extendContext({ cluster_uuid: 'test-cluster-uuid-2', license_id: 'test-license-id-2' }); - expect(getInternalClusterUuid()).toBe('test-cluster-uuid-2'); - expect(getInternalLicenseId()).toBe('test-license-id-2'); - }); - - test('calls to reportEvents do not call `fetch` straight away', () => { - shipper.reportEvents(events); - expect(fetchMock).not.toHaveBeenCalled(); - }); - - test( - 'calls to reportEvents do not call `fetch` after 10 minutes because no optIn value is set yet', - fakeSchedulers((advance) => { - shipper.reportEvents(events); - advance(10 * MINUTES); - expect(fetchMock).not.toHaveBeenCalled(); - }) - ); - - test( - 'calls to reportEvents call `fetch` after 10 seconds when optIn value is set to true', - fakeSchedulers(async (advance) => { - shipper.reportEvents(events); - shipper.optIn(true); - const counter = firstValueFrom(shipper.telemetryCounter$); - setLastBatchSent(Date.now() - 10 * SECONDS); - advance(1 * SECONDS); // Moving 1 second should be enough to trigger the logic - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` - Object { - "code": "200", - "count": 1, - "event_type": "test-event-type", - "source": "elastic_v3_server", - "type": "succeeded", - } - `); - }) - ); - - test( - 'calls to reportEvents do not call `fetch` after 10 seconds when optIn value is set to false', - fakeSchedulers((advance) => { - shipper.reportEvents(events); - shipper.optIn(false); - setLastBatchSent(Date.now() - 10 * SECONDS); - advance(1 * SECONDS); // Moving 1 second should be enough to trigger the logic - expect(fetchMock).not.toHaveBeenCalled(); - }) - ); - - test('calls to reportEvents call `fetch` when shutting down if optIn value is set to true', async () => { - shipper.reportEvents(events); - shipper.optIn(true); - const counter = firstValueFrom(shipper.telemetryCounter$); - shipper.shutdown(); - await nextTick(); // We are handling the shutdown in a promise, so we need to wait for the next tick. - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` - Object { - "code": "200", - "count": 1, - "event_type": "test-event-type", - "source": "elastic_v3_server", - "type": "succeeded", - } - `); - }); - - test( - 'does not add the query.debug: true property to the request if the shipper is not set with the debug flag', - fakeSchedulers((advance) => { - shipper = new ElasticV3ServerShipper( - { version: '1.2.3', channelName: 'test-channel' }, - initContext - ); - // eslint-disable-next-line dot-notation - shipper['firstTimeOffline'] = null; - shipper.reportEvents(events); - shipper.optIn(true); - setLastBatchSent(Date.now() - 10 * SECONDS); - advance(1 * SECONDS); // Moving 1 second should be enough to trigger the logic - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - method: 'POST', - } - ); - }) - ); - - test( - 'sends when the queue overflows the 10kB leaky bucket one batch every 10s', - fakeSchedulers(async (advance) => { - expect.assertions(2 * 9 + 2); - - shipper.reportEvents(new Array(1000).fill(events[0])); - shipper.optIn(true); - - // Due to the size of the test events, it matches 8 rounds. - for (let i = 0; i < 9; i++) { - const counter = firstValueFrom(shipper.telemetryCounter$); - setLastBatchSent(Date.now() - 10 * SECONDS); - advance(1 * SECONDS); // Moving 1 second should be enough to trigger the logic - expect(fetchMock).toHaveBeenNthCalledWith( - i + 1, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: new Array(103) - .fill( - '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n' - ) - .join(''), - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` - Object { - "code": "200", - "count": 103, - "event_type": "test-event-type", - "source": "elastic_v3_server", - "type": "succeeded", - } - `); - await nextTick(); - } - // eslint-disable-next-line dot-notation - expect(shipper['internalQueue'].length).toBe(1000 - 9 * 103); // 73 - - // If we call it again, it should not enqueue all the events (only the ones to fill the queue): - shipper.reportEvents(new Array(1000).fill(events[0])); - // eslint-disable-next-line dot-notation - expect(shipper['internalQueue'].length).toBe(1000); - }) - ); - - test( - 'handles when the fetch request fails', - fakeSchedulers(async (advance) => { - fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); - shipper.reportEvents(events); - shipper.optIn(true); - const counter = firstValueFrom(shipper.telemetryCounter$); - setLastBatchSent(Date.now() - 10 * SECONDS); - advance(1 * SECONDS); // Moving 1 second should be enough to trigger the logic - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` - Object { - "code": "Failed to fetch", - "count": 1, - "event_type": "test-event-type", - "source": "elastic_v3_server", - "type": "failed", - } - `); - }) - ); - - test( - 'handles when the fetch request fails (request completes but not OK response)', - fakeSchedulers(async (advance) => { - fetchMock.mockResolvedValueOnce({ - ok: false, - status: 400, - text: () => Promise.resolve('{"status": "not ok"}'), - }); - shipper.reportEvents(events); - shipper.optIn(true); - const counter = firstValueFrom(shipper.telemetryCounter$); - setLastBatchSent(Date.now() - 10 * SECONDS); - advance(1 * SECONDS); // Moving 1 second should be enough to trigger the logic - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` - Object { - "code": "400", - "count": 1, - "event_type": "test-event-type", - "source": "elastic_v3_server", - "type": "failed", - } - `); - }) - ); - - describe('Connectivity Checks', () => { - describe('connectivity check when connectivity is confirmed (firstTimeOffline === null)', () => { - test.each([undefined, false, true])('does not run for opt-in %p', (optInValue) => - fakeSchedulers(async (advance) => { - if (optInValue !== undefined) { - shipper.optIn(optInValue); - } - - // From the start, it doesn't check connectivity because already confirmed - expect(fetchMock).not.toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - - // Wait a big time (1 minute should be enough, but for the sake of tests...) - advance(10 * MINUTES); - await nextTick(); - - expect(fetchMock).not.toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - })() - ); - }); - - describe('connectivity check with initial unknown state of the connectivity', () => { - beforeEach(() => { - // eslint-disable-next-line dot-notation - shipper['firstTimeOffline'] = undefined; // Initial unknown state of the connectivity - }); - - test.each([undefined, false])('does not run for opt-in %p', (optInValue) => - fakeSchedulers(async (advance) => { - if (optInValue !== undefined) { - shipper.optIn(optInValue); - } - - // From the start, it doesn't check connectivity because already confirmed - expect(fetchMock).not.toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - - // Wait a big time (1 minute should be enough, but for the sake of tests...) - advance(10 * MINUTES); - await nextTick(); - - expect(fetchMock).not.toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - })() - ); - - test('runs as soon as opt-in is set to true', () => { - shipper.optIn(true); - - // From the start, it doesn't check connectivity because opt-in is not true - expect(fetchMock).toHaveBeenNthCalledWith( - 1, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - }); - }); - - describe('connectivity check with the connectivity confirmed to be faulty', () => { - beforeEach(() => { - // eslint-disable-next-line dot-notation - shipper['firstTimeOffline'] = 100; // Failed at some point - }); - - test.each([undefined, false])('does not run for opt-in %p', (optInValue) => - fakeSchedulers(async (advance) => { - if (optInValue !== undefined) { - shipper.optIn(optInValue); - } - - // From the start, it doesn't check connectivity because already confirmed - expect(fetchMock).not.toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - - // Wait a big time (1 minute should be enough, but for the sake of tests...) - advance(10 * MINUTES); - await nextTick(); - - expect(fetchMock).not.toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - })() - ); - - test('runs as soon as opt-in is set to true', () => { - shipper.optIn(true); - - // From the start, it doesn't check connectivity because opt-in is not true - expect(fetchMock).toHaveBeenNthCalledWith( - 1, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - }); - }); - - describe('after report failure', () => { - // generate the report failure for each test - beforeEach( - fakeSchedulers(async (advance) => { - fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); - shipper.reportEvents(events); - shipper.optIn(true); - const counter = firstValueFrom(shipper.telemetryCounter$); - setLastBatchSent(Date.now() - 10 * SECONDS); - advance(1 * SECONDS); // Moving 1 second should be enough to trigger the logic - expect(fetchMock).toHaveBeenNthCalledWith( - 1, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - method: 'POST', - query: { debug: true }, - } - ); - await expect(counter).resolves.toMatchInlineSnapshot(` - Object { - "code": "Failed to fetch", - "count": 1, - "event_type": "test-event-type", - "source": "elastic_v3_server", - "type": "failed", - } - `); - }) - ); - - test( - 'connectivity check runs periodically', - fakeSchedulers(async (advance) => { - fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); - advance(1 * MINUTES); - await nextTick(); - expect(fetchMock).toHaveBeenNthCalledWith( - 2, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - fetchMock.mockResolvedValueOnce({ ok: false }); - advance(2 * MINUTES); - await nextTick(); - expect(fetchMock).toHaveBeenNthCalledWith( - 3, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - }) - ); - }); - - describe('after being offline for longer than 24h', () => { - beforeEach(() => { - shipper.optIn(true); - shipper.reportEvents(events); - // eslint-disable-next-line dot-notation - expect(shipper['internalQueue'].length).toBe(1); - // eslint-disable-next-line dot-notation - shipper['firstTimeOffline'] = 100; - }); - - test( - 'the following connectivity check clears the queue', - fakeSchedulers(async (advance) => { - fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); - advance(1 * MINUTES); - await nextTick(); - expect(fetchMock).toHaveBeenNthCalledWith( - 1, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - // eslint-disable-next-line dot-notation - expect(shipper['internalQueue'].length).toBe(0); - }) - ); - - test( - 'new events are not added to the queue', - fakeSchedulers(async (advance) => { - fetchMock.mockRejectedValueOnce(new Error('Failed to fetch')); - advance(1 * MINUTES); - await nextTick(); - expect(fetchMock).toHaveBeenNthCalledWith( - 1, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - // eslint-disable-next-line dot-notation - expect(shipper['internalQueue'].length).toBe(0); - - shipper.reportEvents(events); - // eslint-disable-next-line dot-notation - expect(shipper['internalQueue'].length).toBe(0); - }) - ); - - test( - 'regains the connection', - fakeSchedulers(async (advance) => { - fetchMock.mockResolvedValueOnce({ ok: true }); - advance(1 * MINUTES); - await nextTick(); - expect(fetchMock).toHaveBeenNthCalledWith( - 1, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - // eslint-disable-next-line dot-notation - expect(shipper['firstTimeOffline']).toBe(null); - - advance(10 * MINUTES); - await nextTick(); - expect(fetchMock).not.toHaveBeenNthCalledWith( - 2, - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { method: 'OPTIONS' } - ); - }) - ); - }); - }); - - describe('flush method', () => { - test('resolves straight away if it should not send anything', async () => { - await expect(shipper.flush()).resolves.toBe(undefined); - }); - - test('resolves when all the ongoing requests are complete', async () => { - shipper.optIn(true); - shipper.reportEvents(events); - expect(fetchMock).toHaveBeenCalledTimes(0); - fetchMock.mockImplementation(async () => { - // eslint-disable-next-line dot-notation - expect(shipper['inFlightRequests$'].value).toBe(1); - }); - await expect(shipper.flush()).resolves.toBe(undefined); - expect(fetchMock).toHaveBeenCalledWith( - 'https://telemetry-staging.elastic.co/v3/send/test-channel', - { - body: '{"timestamp":"2020-01-01T00:00:00.000Z","event_type":"test-event-type","context":{},"properties":{}}\n', - headers: { - 'content-type': 'application/x-ndjson', - 'x-elastic-cluster-id': 'UNKNOWN', - 'x-elastic-stack-version': '1.2.3', - }, - method: 'POST', - query: { debug: true }, - } - ); - }); - - test('calling flush multiple times does not keep hanging', async () => { - await expect(shipper.flush()).resolves.toBe(undefined); - await expect(shipper.flush()).resolves.toBe(undefined); - await Promise.all([shipper.flush(), shipper.flush()]); - }); - - test('calling flush after shutdown does not keep hanging', async () => { - shipper.shutdown(); - await expect(shipper.flush()).resolves.toBe(undefined); - }); - }); -}); diff --git a/packages/analytics/shippers/elastic_v3/server/tsconfig.json b/packages/analytics/shippers/elastic_v3/server/tsconfig.json deleted file mode 100644 index 7808dee7058f00..00000000000000 --- a/packages/analytics/shippers/elastic_v3/server/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "../../../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/analytics-client", - "@kbn/analytics-shippers-elastic-v3-common", - "@kbn/logging-mocks" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/analytics/shippers/fullstory/jest.config.js b/packages/analytics/shippers/fullstory/jest.config.js deleted file mode 100644 index 9d1637823c1505..00000000000000 --- a/packages/analytics/shippers/fullstory/jest.config.js +++ /dev/null @@ -1,13 +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. - */ - -module.exports = { - preset: '@kbn/test/jest_node', - rootDir: '../../../../', - roots: ['/packages/analytics/shippers/fullstory'], -}; diff --git a/packages/analytics/shippers/fullstory/kibana.jsonc b/packages/analytics/shippers/fullstory/kibana.jsonc deleted file mode 100644 index d2848e7b3c4538..00000000000000 --- a/packages/analytics/shippers/fullstory/kibana.jsonc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "shared-common", - "id": "@kbn/analytics-shippers-fullstory", - "owner": "@elastic/kibana-core" -} diff --git a/packages/analytics/shippers/fullstory/package.json b/packages/analytics/shippers/fullstory/package.json deleted file mode 100644 index 4eca1476236a1a..00000000000000 --- a/packages/analytics/shippers/fullstory/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@kbn/analytics-shippers-fullstory", - "private": true, - "version": "1.0.0", - "author": "Kibana Core", - "license": "SSPL-1.0 OR Elastic License 2.0" -} \ No newline at end of file diff --git a/packages/analytics/shippers/fullstory/tsconfig.json b/packages/analytics/shippers/fullstory/tsconfig.json deleted file mode 100644 index 00a680d9c6f2c5..00000000000000 --- a/packages/analytics/shippers/fullstory/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "../../../../tsconfig.base.json", - "compilerOptions": { - "outDir": "target/types", - "types": [ - "jest", - "node" - ] - }, - "include": [ - "**/*.ts" - ], - "kbn_references": [ - "@kbn/analytics-client", - "@kbn/logging-mocks", - "@kbn/safer-lodash-set" - ], - "exclude": [ - "target/**/*", - ] -} diff --git a/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts b/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts index 7f32ea7ed41a62..ec9d9e05aff232 100644 --- a/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts +++ b/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { AnalyticsClient } from '@kbn/analytics-client'; +import { AnalyticsClient } from '@kbn/ebt/client'; import { Subject } from 'rxjs'; export const analyticsClientMock: jest.Mocked = { @@ -21,6 +21,6 @@ export const analyticsClientMock: jest.Mocked = { shutdown: jest.fn(), }; -jest.doMock('@kbn/analytics-client', () => ({ +jest.doMock('@kbn/ebt/client', () => ({ createAnalytics: () => analyticsClientMock, })); diff --git a/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts b/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts index 25ea7aed65afc9..091643741331ea 100644 --- a/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts +++ b/packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts @@ -7,8 +7,8 @@ */ import { of, Subscription } from 'rxjs'; -import type { AnalyticsClient } from '@kbn/analytics-client'; -import { createAnalytics } from '@kbn/analytics-client'; +import type { AnalyticsClient } from '@kbn/ebt/client'; +import { createAnalytics } from '@kbn/ebt/client'; import { registerPerformanceMetricEventType } from '@kbn/ebt-tools'; import type { CoreContext } from '@kbn/core-base-browser-internal'; import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal'; diff --git a/packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts b/packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts index 6ca58e7d69149d..e545ec0fe7b2a4 100644 --- a/packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts +++ b/packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts @@ -7,7 +7,7 @@ */ import { fromEvent } from 'rxjs'; -import type { AnalyticsClient } from '@kbn/analytics-client'; +import type { AnalyticsClient } from '@kbn/ebt/client'; /** HTML attributes that should be skipped from reporting because they might contain data we do not wish to collect */ const HTML_ATTRIBUTES_TO_REMOVE = [ diff --git a/packages/core/analytics/core-analytics-browser-internal/src/track_performance_measure_entries.ts b/packages/core/analytics/core-analytics-browser-internal/src/track_performance_measure_entries.ts index 80826c03864adc..40d479b448b462 100644 --- a/packages/core/analytics/core-analytics-browser-internal/src/track_performance_measure_entries.ts +++ b/packages/core/analytics/core-analytics-browser-internal/src/track_performance_measure_entries.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 type { AnalyticsClient } from '@kbn/analytics-client'; +import type { AnalyticsClient } from '@kbn/ebt/client'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; export function trackPerformanceMeasureEntries(analytics: AnalyticsClient, isDevMode: boolean) { diff --git a/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts b/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts index 17fab459f2e8fa..dd0ebde28addbc 100644 --- a/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts +++ b/packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts @@ -7,7 +7,7 @@ */ import { debounceTime, fromEvent, map, merge, of, shareReplay } from 'rxjs'; -import type { AnalyticsClient, RootSchema } from '@kbn/analytics-client'; +import type { AnalyticsClient, RootSchema } from '@kbn/ebt/client'; export interface ViewportSize { viewport_width: number; diff --git a/packages/core/analytics/core-analytics-browser-internal/tsconfig.json b/packages/core/analytics/core-analytics-browser-internal/tsconfig.json index a58f3402e65a9a..ecac1746f44a28 100644 --- a/packages/core/analytics/core-analytics-browser-internal/tsconfig.json +++ b/packages/core/analytics/core-analytics-browser-internal/tsconfig.json @@ -6,13 +6,13 @@ }, "include": ["**/*.ts"], "kbn_references": [ - "@kbn/analytics-client", "@kbn/ebt-tools", "@kbn/core-base-browser-internal", "@kbn/core-injected-metadata-browser-internal", "@kbn/core-analytics-browser", "@kbn/core-base-browser-mocks", "@kbn/core-injected-metadata-browser-mocks", + "@kbn/ebt", ], "exclude": ["target/**/*"] } diff --git a/packages/core/analytics/core-analytics-browser/index.ts b/packages/core/analytics/core-analytics-browser/index.ts index 331f1695d9f201..f20ccf31da2c44 100644 --- a/packages/core/analytics/core-analytics-browser/index.ts +++ b/packages/core/analytics/core-analytics-browser/index.ts @@ -11,3 +11,41 @@ export type { AnalyticsServiceStart, KbnAnalyticsWindowApi, } from './src/types'; + +export type { + AnalyticsClient, + AnalyticsClientInitContext, + // Types for the registerShipper API + ShipperClassConstructor, + RegisterShipperOpts, + // Types for the optIn API + OptInConfig, + OptInConfigPerType, + ShipperName, + // Types for the registerContextProvider API + ContextProviderOpts, + ContextProviderName, + // Types for the registerEventType API + EventTypeOpts, + // Events + Event, + EventContext, + EventType, + TelemetryCounter, + TelemetryCounterType, + // Schema + RootSchema, + SchemaObject, + SchemaArray, + SchemaChildValue, + SchemaMeta, + SchemaValue, + SchemaMetaOptional, + PossibleSchemaTypes, + AllowedSchemaBooleanTypes, + AllowedSchemaNumberTypes, + AllowedSchemaStringTypes, + AllowedSchemaTypes, + // Shippers + IShipper, +} from '@kbn/ebt/client'; diff --git a/packages/core/analytics/core-analytics-browser/src/types.ts b/packages/core/analytics/core-analytics-browser/src/types.ts index dbc35043613cd3..779172acc9b9dd 100644 --- a/packages/core/analytics/core-analytics-browser/src/types.ts +++ b/packages/core/analytics/core-analytics-browser/src/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { AnalyticsClient } from '@kbn/analytics-client'; +import type { AnalyticsClient } from '@kbn/ebt/client'; /** * Exposes the public APIs of the AnalyticsClient during the setup phase. diff --git a/packages/core/analytics/core-analytics-browser/tsconfig.json b/packages/core/analytics/core-analytics-browser/tsconfig.json index 9c3a721a57e23f..83571abe4bcf41 100644 --- a/packages/core/analytics/core-analytics-browser/tsconfig.json +++ b/packages/core/analytics/core-analytics-browser/tsconfig.json @@ -11,7 +11,7 @@ "**/*.ts" ], "kbn_references": [ - "@kbn/analytics-client" + "@kbn/ebt", ], "exclude": [ "target/**/*", diff --git a/packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts b/packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts index a3bd814f1e32f6..d759a9520cc161 100644 --- a/packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts +++ b/packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { AnalyticsClient } from '@kbn/analytics-client'; +import { AnalyticsClient } from '@kbn/ebt/client'; import { Subject } from 'rxjs'; export const analyticsClientMock: jest.Mocked = { @@ -21,6 +21,6 @@ export const analyticsClientMock: jest.Mocked = { flush: jest.fn(), }; -jest.doMock('@kbn/analytics-client', () => ({ +jest.doMock('@kbn/ebt/client', () => ({ createAnalytics: () => analyticsClientMock, })); diff --git a/packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts b/packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts index 141f5b9970c0bf..8e0ce76e08b965 100644 --- a/packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts +++ b/packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts @@ -7,8 +7,8 @@ */ import { of } from 'rxjs'; -import type { AnalyticsClient } from '@kbn/analytics-client'; -import { createAnalytics } from '@kbn/analytics-client'; +import type { AnalyticsClient } from '@kbn/ebt/client'; +import { createAnalytics } from '@kbn/ebt/client'; import { registerPerformanceMetricEventType } from '@kbn/ebt-tools'; import type { CoreContext } from '@kbn/core-base-server-internal'; import type { diff --git a/packages/core/analytics/core-analytics-server-internal/tsconfig.json b/packages/core/analytics/core-analytics-server-internal/tsconfig.json index 56292065f7af65..57a0fa3e043623 100644 --- a/packages/core/analytics/core-analytics-server-internal/tsconfig.json +++ b/packages/core/analytics/core-analytics-server-internal/tsconfig.json @@ -11,12 +11,12 @@ "**/*.ts" ], "kbn_references": [ - "@kbn/analytics-client", "@kbn/ebt-tools", "@kbn/core-base-server-internal", "@kbn/core-analytics-server", "@kbn/config-mocks", "@kbn/core-base-server-mocks", + "@kbn/ebt", ], "exclude": [ "target/**/*", diff --git a/packages/core/analytics/core-analytics-server/index.ts b/packages/core/analytics/core-analytics-server/index.ts index c9a91ca3a8866b..90341deb693a3a 100644 --- a/packages/core/analytics/core-analytics-server/index.ts +++ b/packages/core/analytics/core-analytics-server/index.ts @@ -11,3 +11,41 @@ export type { AnalyticsServiceStart, AnalyticsServicePreboot, } from './src/contracts'; + +export type { + AnalyticsClient, + AnalyticsClientInitContext, + // Types for the registerShipper API + ShipperClassConstructor, + RegisterShipperOpts, + // Types for the optIn API + OptInConfig, + OptInConfigPerType, + ShipperName, + // Types for the registerContextProvider API + ContextProviderOpts, + ContextProviderName, + // Types for the registerEventType API + EventTypeOpts, + // Events + Event, + EventContext, + EventType, + TelemetryCounter, + TelemetryCounterType, + // Schema + RootSchema, + SchemaObject, + SchemaArray, + SchemaChildValue, + SchemaMeta, + SchemaValue, + SchemaMetaOptional, + PossibleSchemaTypes, + AllowedSchemaBooleanTypes, + AllowedSchemaNumberTypes, + AllowedSchemaStringTypes, + AllowedSchemaTypes, + // Shippers + IShipper, +} from '@kbn/ebt/client'; diff --git a/packages/core/analytics/core-analytics-server/src/contracts.ts b/packages/core/analytics/core-analytics-server/src/contracts.ts index 4879b988b1752e..531c4ef6afd1fe 100644 --- a/packages/core/analytics/core-analytics-server/src/contracts.ts +++ b/packages/core/analytics/core-analytics-server/src/contracts.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { AnalyticsClient } from '@kbn/analytics-client'; +import type { AnalyticsClient } from '@kbn/ebt/client'; /** * Exposes the public APIs of the AnalyticsClient during the preboot phase diff --git a/packages/core/analytics/core-analytics-server/tsconfig.json b/packages/core/analytics/core-analytics-server/tsconfig.json index 9c3a721a57e23f..aa81d68980cd99 100644 --- a/packages/core/analytics/core-analytics-server/tsconfig.json +++ b/packages/core/analytics/core-analytics-server/tsconfig.json @@ -11,7 +11,7 @@ "**/*.ts" ], "kbn_references": [ - "@kbn/analytics-client" + "@kbn/ebt" ], "exclude": [ "target/**/*", diff --git a/packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_types.ts b/packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_types.ts index 7c4b08cd8647dd..35e012fe2f625a 100644 --- a/packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_types.ts +++ b/packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { type RootSchema, type EventTypeOpts } from '@kbn/analytics-client'; +import { type RootSchema, type EventTypeOpts } from '@kbn/ebt/client'; export enum EventMetric { TOAST_DISMISSED = 'global_toast_list_toast_dismissed', diff --git a/packages/core/notifications/core-notifications-browser-internal/tsconfig.json b/packages/core/notifications/core-notifications-browser-internal/tsconfig.json index 0250d4b80488be..88855bd5bd4bbe 100644 --- a/packages/core/notifications/core-notifications-browser-internal/tsconfig.json +++ b/packages/core/notifications/core-notifications-browser-internal/tsconfig.json @@ -31,7 +31,7 @@ "@kbn/react-kibana-context-render", "@kbn/core-analytics-browser", "@kbn/core-analytics-browser-mocks", - "@kbn/analytics-client", + "@kbn/ebt", ], "exclude": [ "target/**/*", diff --git a/packages/core/status/core-status-server-internal/src/status_service.ts b/packages/core/status/core-status-server-internal/src/status_service.ts index 3947f04c615744..a24153342543cd 100644 --- a/packages/core/status/core-status-server-internal/src/status_service.ts +++ b/packages/core/status/core-status-server-internal/src/status_service.ts @@ -18,7 +18,7 @@ import { import { map, distinctUntilChanged, shareReplay, takeUntil, debounceTime } from 'rxjs'; import { isDeepStrictEqual } from 'util'; -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/ebt/client'; import type { Logger, LogMeta } from '@kbn/logging'; import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; import type { PluginName } from '@kbn/core-base-common'; diff --git a/packages/core/status/core-status-server-internal/tsconfig.json b/packages/core/status/core-status-server-internal/tsconfig.json index 0cc9f82b847945..42d4e92c57e0ab 100644 --- a/packages/core/status/core-status-server-internal/tsconfig.json +++ b/packages/core/status/core-status-server-internal/tsconfig.json @@ -16,7 +16,6 @@ "@kbn/std", "@kbn/logging", "@kbn/i18n", - "@kbn/analytics-client", "@kbn/core-base-common", "@kbn/core-base-server-internal", "@kbn/core-http-server", @@ -42,6 +41,7 @@ "@kbn/core-analytics-server-mocks", "@kbn/core-logging-server-internal", "@kbn/core-logging-server-mocks", + "@kbn/ebt", ], "exclude": [ "target/**/*", diff --git a/packages/kbn-ebt-tools/src/performance_metric_events/helpers.test.ts b/packages/kbn-ebt-tools/src/performance_metric_events/helpers.test.ts index a6ad3970a6a976..de4271a474961a 100644 --- a/packages/kbn-ebt-tools/src/performance_metric_events/helpers.test.ts +++ b/packages/kbn-ebt-tools/src/performance_metric_events/helpers.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { createAnalytics, type AnalyticsClient } from '@kbn/analytics-client'; +import { createAnalytics, type AnalyticsClient } from '@kbn/ebt/client'; import { loggerMock } from '@kbn/logging-mocks'; import { registerPerformanceMetricEventType, reportPerformanceMetricEvent } from './helpers'; import { METRIC_EVENT_SCHEMA } from './schema'; diff --git a/packages/kbn-ebt-tools/src/performance_metric_events/helpers.ts b/packages/kbn-ebt-tools/src/performance_metric_events/helpers.ts index f9aecd2bd7ec93..2763222c60d1fe 100644 --- a/packages/kbn-ebt-tools/src/performance_metric_events/helpers.ts +++ b/packages/kbn-ebt-tools/src/performance_metric_events/helpers.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { AnalyticsClient } from '@kbn/analytics-client'; +import type { AnalyticsClient } from '@kbn/ebt/client'; import { type PerformanceMetricEvent, METRIC_EVENT_SCHEMA } from './schema'; const PERFORMANCE_METRIC_EVENT_TYPE = 'performance_metric'; diff --git a/packages/kbn-ebt-tools/src/performance_metric_events/schema.ts b/packages/kbn-ebt-tools/src/performance_metric_events/schema.ts index 15fdb4a1e9b33f..b841b9b8d6f1d7 100644 --- a/packages/kbn-ebt-tools/src/performance_metric_events/schema.ts +++ b/packages/kbn-ebt-tools/src/performance_metric_events/schema.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/ebt/client'; /** * Structure of the `metric` event diff --git a/packages/kbn-ebt-tools/tsconfig.json b/packages/kbn-ebt-tools/tsconfig.json index 7dd6d0703f0732..881349b3f4d9be 100644 --- a/packages/kbn-ebt-tools/tsconfig.json +++ b/packages/kbn-ebt-tools/tsconfig.json @@ -5,6 +5,9 @@ "types": ["jest", "node"] }, "include": ["**/*.ts", "**/*.tsx"], - "kbn_references": ["@kbn/analytics-client", "@kbn/logging-mocks"], + "kbn_references": [ + "@kbn/logging-mocks", + "@kbn/ebt", + ], "exclude": ["target/**/*"] } diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 2260b78f90d9a8..372eabdac9c95b 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -96,20 +96,46 @@ export type { UiSettingsType, } from '@kbn/core-ui-settings-common'; -export type { AnalyticsServiceSetup, AnalyticsServiceStart } from '@kbn/core-analytics-browser'; export type { AnalyticsClient, - Event, - EventContext, - EventType, - EventTypeOpts, - IShipper, + AnalyticsClientInitContext, + AnalyticsServiceSetup, + AnalyticsServiceStart, + KbnAnalyticsWindowApi, + // Types for the registerShipper API ShipperClassConstructor, + RegisterShipperOpts, + // Types for the optIn API OptInConfig, + OptInConfigPerType, + ShipperName, + // Types for the registerContextProvider API ContextProviderOpts, + ContextProviderName, + // Types for the registerEventType API + EventTypeOpts, + // Events + Event, + EventContext, + EventType, TelemetryCounter, TelemetryCounterType, -} from '@kbn/analytics-client'; + // Schema + RootSchema, + SchemaObject, + SchemaArray, + SchemaChildValue, + SchemaMeta, + SchemaValue, + SchemaMetaOptional, + PossibleSchemaTypes, + AllowedSchemaBooleanTypes, + AllowedSchemaNumberTypes, + AllowedSchemaStringTypes, + AllowedSchemaTypes, + // Shippers + IShipper, +} from '@kbn/core-analytics-browser'; export { AppStatus } from '@kbn/core-application-browser'; export type { diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 901e0e31536515..1e89c9ed5b24e6 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -482,21 +482,43 @@ export type { DocLinksServiceStart, DocLinksServiceSetup } from '@kbn/core-doc-l export type { AnalyticsClient, + AnalyticsClientInitContext, + AnalyticsServiceSetup, + AnalyticsServicePreboot, + AnalyticsServiceStart, + // Types for the registerShipper API + ShipperClassConstructor, + RegisterShipperOpts, + // Types for the optIn API + OptInConfig, + OptInConfigPerType, + ShipperName, + // Types for the registerContextProvider API + ContextProviderOpts, + ContextProviderName, + // Types for the registerEventType API + EventTypeOpts, + // Events Event, EventContext, EventType, - EventTypeOpts, - IShipper, - ContextProviderOpts, - OptInConfig, - ShipperClassConstructor, TelemetryCounter, TelemetryCounterType, -} from '@kbn/analytics-client'; -export type { - AnalyticsServiceSetup, - AnalyticsServicePreboot, - AnalyticsServiceStart, + // Schema + RootSchema, + SchemaObject, + SchemaArray, + SchemaChildValue, + SchemaMeta, + SchemaValue, + SchemaMetaOptional, + PossibleSchemaTypes, + AllowedSchemaBooleanTypes, + AllowedSchemaNumberTypes, + AllowedSchemaStringTypes, + AllowedSchemaTypes, + // Shippers + IShipper, } from '@kbn/core-analytics-server'; export type { RequestHandlerContext, diff --git a/src/core/tsconfig.json b/src/core/tsconfig.json index 05ae89cb1be93f..017ffa69c31079 100644 --- a/src/core/tsconfig.json +++ b/src/core/tsconfig.json @@ -124,7 +124,6 @@ "@kbn/core-deprecations-common", "@kbn/core-status-server", "@kbn/core-doc-links-server", - "@kbn/analytics-client", "@kbn/core-analytics-server", "@kbn/core-lifecycle-server", "@kbn/core-doc-links-browser", diff --git a/src/plugins/kibana_usage_collection/public/ebt_counters/register_ebt_counters.test.ts b/src/plugins/kibana_usage_collection/public/ebt_counters/register_ebt_counters.test.ts index a546f54f52261f..9e2be1c709f0a6 100644 --- a/src/plugins/kibana_usage_collection/public/ebt_counters/register_ebt_counters.test.ts +++ b/src/plugins/kibana_usage_collection/public/ebt_counters/register_ebt_counters.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { TelemetryCounter } from '@kbn/analytics-client'; +import type { TelemetryCounter } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/public/mocks'; import { registerEbtCounters } from './register_ebt_counters'; diff --git a/src/plugins/kibana_usage_collection/server/ebt_counters/register_ebt_counters.test.ts b/src/plugins/kibana_usage_collection/server/ebt_counters/register_ebt_counters.test.ts index c58a81dda10e66..a2ac2366c0b3e1 100644 --- a/src/plugins/kibana_usage_collection/server/ebt_counters/register_ebt_counters.test.ts +++ b/src/plugins/kibana_usage_collection/server/ebt_counters/register_ebt_counters.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { TelemetryCounter } from '@kbn/analytics-client'; +import type { TelemetryCounter } from '@kbn/core/server'; import { coreMock } from '@kbn/core/server/mocks'; import { createUsageCollectionSetupMock } from '@kbn/usage-collection-plugin/server/mocks'; import { registerEbtCounters } from './register_ebt_counters'; diff --git a/src/plugins/kibana_usage_collection/tsconfig.json b/src/plugins/kibana_usage_collection/tsconfig.json index d56cb860cd463a..2fb915d5410520 100644 --- a/src/plugins/kibana_usage_collection/tsconfig.json +++ b/src/plugins/kibana_usage_collection/tsconfig.json @@ -13,7 +13,6 @@ "kbn_references": [ "@kbn/core", "@kbn/usage-collection-plugin", - "@kbn/analytics-client", "@kbn/i18n", "@kbn/logging", "@kbn/core-test-helpers-kbn-server", diff --git a/src/plugins/telemetry/public/plugin.test.ts b/src/plugins/telemetry/public/plugin.test.ts index 842e11f12cc687..f943f2cae86d15 100644 --- a/src/plugins/telemetry/public/plugin.test.ts +++ b/src/plugins/telemetry/public/plugin.test.ts @@ -7,7 +7,7 @@ */ import { of } from 'rxjs'; -import { ElasticV3BrowserShipper } from '@kbn/analytics-shippers-elastic-v3-browser'; +import { ElasticV3BrowserShipper } from '@kbn/ebt/shippers/elastic_v3/browser'; import { coreMock } from '@kbn/core/public/mocks'; import { homePluginMock } from '@kbn/home-plugin/public/mocks'; import { screenshotModePluginMock } from '@kbn/screenshot-mode-plugin/public/mocks'; diff --git a/src/plugins/telemetry/public/plugin.ts b/src/plugins/telemetry/public/plugin.ts index 26a4f50af96ca5..9b5a2c3af596aa 100644 --- a/src/plugins/telemetry/public/plugin.ts +++ b/src/plugins/telemetry/public/plugin.ts @@ -22,7 +22,7 @@ import type { ScreenshotModePluginStart, } from '@kbn/screenshot-mode-plugin/public'; import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; -import { ElasticV3BrowserShipper } from '@kbn/analytics-shippers-elastic-v3-browser'; +import { ElasticV3BrowserShipper } from '@kbn/ebt/shippers/elastic_v3/browser'; import { isSyntheticsMonitor } from '@kbn/analytics-collection-utils'; import { BehaviorSubject, map, switchMap, tap } from 'rxjs'; diff --git a/src/plugins/telemetry/server/plugin.test.ts b/src/plugins/telemetry/server/plugin.test.ts index 7d997bbc7c5287..6410deb2daa594 100644 --- a/src/plugins/telemetry/server/plugin.test.ts +++ b/src/plugins/telemetry/server/plugin.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ElasticV3ServerShipper } from '@kbn/analytics-shippers-elastic-v3-server'; +import { ElasticV3ServerShipper } from '@kbn/ebt/shippers/elastic_v3/server'; import { coreMock } from '@kbn/core/server/mocks'; import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/server/mocks'; import { telemetryCollectionManagerPluginMock } from '@kbn/telemetry-collection-manager-plugin/server/mocks'; diff --git a/src/plugins/telemetry/server/plugin.ts b/src/plugins/telemetry/server/plugin.ts index 394bfa18cb21e1..be8f298218e0f3 100644 --- a/src/plugins/telemetry/server/plugin.ts +++ b/src/plugins/telemetry/server/plugin.ts @@ -22,7 +22,7 @@ import { map, } from 'rxjs'; -import { ElasticV3ServerShipper } from '@kbn/analytics-shippers-elastic-v3-server'; +import { ElasticV3ServerShipper } from '@kbn/ebt/shippers/elastic_v3/server'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import type { diff --git a/src/plugins/telemetry/tsconfig.json b/src/plugins/telemetry/tsconfig.json index 89d15d4f5a0a7b..c6198c377832e0 100644 --- a/src/plugins/telemetry/tsconfig.json +++ b/src/plugins/telemetry/tsconfig.json @@ -20,12 +20,10 @@ "@kbn/telemetry-collection-manager-plugin", "@kbn/usage-collection-plugin", "@kbn/security-plugin", - "@kbn/analytics-shippers-elastic-v3-browser", "@kbn/test-jest-helpers", "@kbn/shared-ux-utility", "@kbn/i18n", "@kbn/i18n-react", - "@kbn/analytics-shippers-elastic-v3-server", "@kbn/config-schema", "@kbn/utils", "@kbn/core-saved-objects-server", @@ -37,6 +35,7 @@ "@kbn/analytics-collection-utils", "@kbn/react-kibana-mount", "@kbn/core-node-server", + "@kbn/ebt", ], "exclude": [ "target/**/*", diff --git a/src/plugins/usage_collection/server/collector/types.ts b/src/plugins/usage_collection/server/collector/types.ts index 50a04560e384b6..9c1802348a113f 100644 --- a/src/plugins/usage_collection/server/collector/types.ts +++ b/src/plugins/usage_collection/server/collector/types.ts @@ -8,7 +8,7 @@ import type { ElasticsearchClient, SavedObjectsClientContract, Logger } from '@kbn/core/server'; -import type { PossibleSchemaTypes, SchemaMetaOptional } from '@kbn/analytics-client'; +import type { PossibleSchemaTypes, SchemaMetaOptional } from '@kbn/ebt/client'; export type { AllowedSchemaTypes, @@ -16,7 +16,7 @@ export type { AllowedSchemaBooleanTypes, AllowedSchemaNumberTypes, PossibleSchemaTypes, -} from '@kbn/analytics-client'; +} from '@kbn/ebt/client'; /** * Helper to find out whether to keep recursively looking or if we are on an end value diff --git a/src/plugins/usage_collection/tsconfig.json b/src/plugins/usage_collection/tsconfig.json index d7cf3f1e4c19f5..e7c24d604be96f 100644 --- a/src/plugins/usage_collection/tsconfig.json +++ b/src/plugins/usage_collection/tsconfig.json @@ -17,12 +17,12 @@ "@kbn/config-schema", "@kbn/screenshot-mode-plugin", "@kbn/std", - "@kbn/analytics-client", "@kbn/utility-types", "@kbn/i18n", "@kbn/core-http-server-mocks", "@kbn/analytics-collection-utils", "@kbn/logging", + "@kbn/ebt", ], "exclude": [ "target/**/*", diff --git a/test/analytics/plugins/analytics_ftr_helpers/common/fetch_events.ts b/test/analytics/plugins/analytics_ftr_helpers/common/fetch_events.ts index 5a5eeba914b7ba..9a2e235a0aa6ac 100644 --- a/test/analytics/plugins/analytics_ftr_helpers/common/fetch_events.ts +++ b/test/analytics/plugins/analytics_ftr_helpers/common/fetch_events.ts @@ -18,7 +18,7 @@ import { toArray, } from 'rxjs'; import { get } from 'lodash'; -import type { Event } from '@kbn/analytics-client'; +import type { Event } from '@kbn/ebt/client'; import type { GetEventsOptions } from './types'; export async function fetchEvents( diff --git a/test/analytics/plugins/analytics_ftr_helpers/common/types.ts b/test/analytics/plugins/analytics_ftr_helpers/common/types.ts index 97e1faff823a48..25c3a8b738fe23 100644 --- a/test/analytics/plugins/analytics_ftr_helpers/common/types.ts +++ b/test/analytics/plugins/analytics_ftr_helpers/common/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { Event, EventType } from '@kbn/analytics-client'; +import type { Event, EventType } from '@kbn/ebt/client'; export type FiltersOptions = { [key in 'eq' | 'gte' | 'gt' | 'lte' | 'lt']?: unknown; diff --git a/test/analytics/plugins/analytics_ftr_helpers/public/custom_shipper.ts b/test/analytics/plugins/analytics_ftr_helpers/public/custom_shipper.ts index df876da5e9cced..c122c6310e04b8 100644 --- a/test/analytics/plugins/analytics_ftr_helpers/public/custom_shipper.ts +++ b/test/analytics/plugins/analytics_ftr_helpers/public/custom_shipper.ts @@ -7,8 +7,7 @@ */ import { Subject } from 'rxjs'; -import type { AnalyticsClientInitContext } from '@kbn/analytics-client'; -import type { Event, IShipper } from '@kbn/core/public'; +import type { AnalyticsClientInitContext, Event, IShipper } from '@kbn/core/public'; export class CustomShipper implements IShipper { public static shipperName = 'FTR-helpers-shipper'; diff --git a/test/analytics/plugins/analytics_ftr_helpers/server/custom_shipper.ts b/test/analytics/plugins/analytics_ftr_helpers/server/custom_shipper.ts index c1ed593673f817..f15d03efe3d7d1 100644 --- a/test/analytics/plugins/analytics_ftr_helpers/server/custom_shipper.ts +++ b/test/analytics/plugins/analytics_ftr_helpers/server/custom_shipper.ts @@ -7,8 +7,7 @@ */ import { Subject } from 'rxjs'; -import type { AnalyticsClientInitContext } from '@kbn/analytics-client'; -import type { IShipper, Event } from '@kbn/core/server'; +import type { AnalyticsClientInitContext, IShipper, Event } from '@kbn/core/server'; export class CustomShipper implements IShipper { public static shipperName = 'FTR-helpers-shipper'; diff --git a/test/analytics/plugins/analytics_ftr_helpers/tsconfig.json b/test/analytics/plugins/analytics_ftr_helpers/tsconfig.json index c6f087def9b011..352e95c7171148 100644 --- a/test/analytics/plugins/analytics_ftr_helpers/tsconfig.json +++ b/test/analytics/plugins/analytics_ftr_helpers/tsconfig.json @@ -15,8 +15,8 @@ ], "kbn_references": [ "@kbn/core", - "@kbn/analytics-client", "@kbn/std", "@kbn/config-schema", + "@kbn/ebt", ] } diff --git a/test/analytics/tests/instrumented_events/from_the_server/core_overall_status_changed.ts b/test/analytics/tests/instrumented_events/from_the_server/core_overall_status_changed.ts index aa11e352495097..7ca8b420850250 100644 --- a/test/analytics/tests/instrumented_events/from_the_server/core_overall_status_changed.ts +++ b/test/analytics/tests/instrumented_events/from_the_server/core_overall_status_changed.ts @@ -7,7 +7,7 @@ */ import expect from '@kbn/expect'; -import { Event } from '@kbn/analytics-client'; +import { Event } from '@kbn/core/server'; import { FtrProviderContext } from '../../../services'; export default function ({ getService }: FtrProviderContext) { diff --git a/test/tsconfig.json b/test/tsconfig.json index 5028acbc0d8302..33a192fc996c69 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -61,7 +61,6 @@ "@kbn/core-application-browser", "@kbn/screenshot-mode-plugin", "@kbn/dev-utils", - "@kbn/analytics-client", "@kbn/utility-types", "@kbn/dev-proc-runner", "@kbn/enterprise-search-plugin", diff --git a/tsconfig.base.json b/tsconfig.base.json index dda059e9432ee7..9c7e088b966d33 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -64,22 +64,12 @@ "@kbn/ambient-ui-types/*": ["packages/kbn-ambient-ui-types/*"], "@kbn/analytics": ["packages/kbn-analytics"], "@kbn/analytics/*": ["packages/kbn-analytics/*"], - "@kbn/analytics-client": ["packages/analytics/client"], - "@kbn/analytics-client/*": ["packages/analytics/client/*"], "@kbn/analytics-collection-utils": ["packages/analytics/utils/analytics_collection_utils"], "@kbn/analytics-collection-utils/*": ["packages/analytics/utils/analytics_collection_utils/*"], "@kbn/analytics-ftr-helpers-plugin": ["test/analytics/plugins/analytics_ftr_helpers"], "@kbn/analytics-ftr-helpers-plugin/*": ["test/analytics/plugins/analytics_ftr_helpers/*"], "@kbn/analytics-plugin-a-plugin": ["test/analytics/plugins/analytics_plugin_a"], "@kbn/analytics-plugin-a-plugin/*": ["test/analytics/plugins/analytics_plugin_a/*"], - "@kbn/analytics-shippers-elastic-v3-browser": ["packages/analytics/shippers/elastic_v3/browser"], - "@kbn/analytics-shippers-elastic-v3-browser/*": ["packages/analytics/shippers/elastic_v3/browser/*"], - "@kbn/analytics-shippers-elastic-v3-common": ["packages/analytics/shippers/elastic_v3/common"], - "@kbn/analytics-shippers-elastic-v3-common/*": ["packages/analytics/shippers/elastic_v3/common/*"], - "@kbn/analytics-shippers-elastic-v3-server": ["packages/analytics/shippers/elastic_v3/server"], - "@kbn/analytics-shippers-elastic-v3-server/*": ["packages/analytics/shippers/elastic_v3/server/*"], - "@kbn/analytics-shippers-fullstory": ["packages/analytics/shippers/fullstory"], - "@kbn/analytics-shippers-fullstory/*": ["packages/analytics/shippers/fullstory/*"], "@kbn/apm-config-loader": ["packages/kbn-apm-config-loader"], "@kbn/apm-config-loader/*": ["packages/kbn-apm-config-loader/*"], "@kbn/apm-data-access-plugin": ["x-pack/plugins/observability_solution/apm_data_access"], @@ -750,6 +740,8 @@ "@kbn/docs-utils/*": ["packages/kbn-docs-utils/*"], "@kbn/dom-drag-drop": ["packages/kbn-dom-drag-drop"], "@kbn/dom-drag-drop/*": ["packages/kbn-dom-drag-drop/*"], + "@kbn/ebt": ["packages/analytics/ebt"], + "@kbn/ebt/*": ["packages/analytics/ebt/*"], "@kbn/ebt-tools": ["packages/kbn-ebt-tools"], "@kbn/ebt-tools/*": ["packages/kbn-ebt-tools/*"], "@kbn/ecs-data-quality-dashboard": ["x-pack/packages/security-solution/ecs_data_quality_dashboard"], diff --git a/x-pack/plugins/cloud/common/register_cloud_deployment_id_analytics_context.ts b/x-pack/plugins/cloud/common/register_cloud_deployment_id_analytics_context.ts index e907a8bc024b79..204b940c45cd5a 100644 --- a/x-pack/plugins/cloud/common/register_cloud_deployment_id_analytics_context.ts +++ b/x-pack/plugins/cloud/common/register_cloud_deployment_id_analytics_context.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AnalyticsClient } from '@kbn/analytics-client'; +import type { AnalyticsClient } from '@kbn/ebt/client'; import { of } from 'rxjs'; import { parseDeploymentIdFromDeploymentUrl } from './parse_deployment_id_from_deployment_url'; diff --git a/x-pack/plugins/cloud/tsconfig.json b/x-pack/plugins/cloud/tsconfig.json index f5d0f3623fc789..ec6d5881a05312 100644 --- a/x-pack/plugins/cloud/tsconfig.json +++ b/x-pack/plugins/cloud/tsconfig.json @@ -13,10 +13,10 @@ "kbn_references": [ "@kbn/core", "@kbn/usage-collection-plugin", - "@kbn/analytics-client", "@kbn/config-schema", "@kbn/logging-mocks", "@kbn/logging", + "@kbn/ebt", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.ts b/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.ts index a9af52c9a6b318..a3b7207eb3122d 100755 --- a/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.ts +++ b/x-pack/plugins/cloud_integrations/cloud_full_story/public/plugin.ts @@ -69,7 +69,7 @@ export class CloudFullStoryPlugin implements Plugin { } // Keep this import async so that we do not load any FullStory code into the browser when it is disabled. - const { FullStoryShipper } = await import('@kbn/analytics-shippers-fullstory'); + const { FullStoryShipper } = await import('@kbn/ebt/shippers/fullstory'); analytics.registerShipper(FullStoryShipper, { eventTypesAllowlist, fullStoryOrgId, diff --git a/x-pack/plugins/cloud_integrations/cloud_full_story/tsconfig.json b/x-pack/plugins/cloud_integrations/cloud_full_story/tsconfig.json index 47b6a5837a829d..852ce8bb8af86e 100644 --- a/x-pack/plugins/cloud_integrations/cloud_full_story/tsconfig.json +++ b/x-pack/plugins/cloud_integrations/cloud_full_story/tsconfig.json @@ -14,7 +14,7 @@ "@kbn/core", "@kbn/cloud-plugin", "@kbn/config-schema", - "@kbn/analytics-shippers-fullstory", + "@kbn/ebt", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts b/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts index ad25c6b2e976f4..85859b2c232b76 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { EventTypeOpts } from '@kbn/analytics-client'; +import type { EventTypeOpts } from '@kbn/core/server'; export const KNOWLEDGE_BASE_EXECUTION_SUCCESS_EVENT: EventTypeOpts<{ model: string; diff --git a/x-pack/plugins/elastic_assistant/tsconfig.json b/x-pack/plugins/elastic_assistant/tsconfig.json index d4ce180d8496d3..dde693653c04cd 100644 --- a/x-pack/plugins/elastic_assistant/tsconfig.json +++ b/x-pack/plugins/elastic_assistant/tsconfig.json @@ -13,7 +13,6 @@ "../../../typings/**/*" ], "kbn_references": [ - "@kbn/analytics-client", "@kbn/core", "@kbn/core-http-server", "@kbn/licensing-plugin", diff --git a/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts b/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts index 912d0c0413c065..35138145a71418 100644 --- a/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts +++ b/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/core/server'; export const fleetAgentsSchema: RootSchema = { agents_per_version: { diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index 8bee11fed5d0e5..7a8f58732902f0 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -86,7 +86,6 @@ "@kbn/core-saved-objects-api-server-mocks", "@kbn/core-saved-objects-api-server", "@kbn/logging", - "@kbn/analytics-client", "@kbn/core-logging-server-mocks", "@kbn/ml-is-populated-object", "@kbn/utils", diff --git a/x-pack/plugins/global_search_bar/public/telemetry/event_types.ts b/x-pack/plugins/global_search_bar/public/telemetry/event_types.ts index bae58ca05b9504..0b95e531d7f9c0 100644 --- a/x-pack/plugins/global_search_bar/public/telemetry/event_types.ts +++ b/x-pack/plugins/global_search_bar/public/telemetry/event_types.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { RootSchema } from '@kbn/analytics-client'; -import { EventTypeOpts } from '@kbn/core/public'; +import { RootSchema, EventTypeOpts } from '@kbn/core/public'; import { EventMetric, FieldType } from '../types'; const fields: Record>> = { diff --git a/x-pack/plugins/global_search_bar/tsconfig.json b/x-pack/plugins/global_search_bar/tsconfig.json index 1e66c8225abeae..f566b0d86eddcb 100644 --- a/x-pack/plugins/global_search_bar/tsconfig.json +++ b/x-pack/plugins/global_search_bar/tsconfig.json @@ -14,7 +14,6 @@ "@kbn/i18n", "@kbn/saved-objects-tagging-oss-plugin", "@kbn/core-chrome-browser", - "@kbn/analytics-client", "@kbn/react-kibana-context-render", ], "exclude": [ diff --git a/x-pack/plugins/licensing/common/register_analytics_context_provider.ts b/x-pack/plugins/licensing/common/register_analytics_context_provider.ts index 60f3fbbb3e6033..5defe217901b2d 100644 --- a/x-pack/plugins/licensing/common/register_analytics_context_provider.ts +++ b/x-pack/plugins/licensing/common/register_analytics_context_provider.ts @@ -7,7 +7,7 @@ import type { Observable } from 'rxjs'; import { map } from 'rxjs'; -import type { AnalyticsClient } from '@kbn/analytics-client'; +import type { AnalyticsClient } from '@kbn/ebt/client'; import type { ILicense } from './types'; export function registerAnalyticsContextProvider( diff --git a/x-pack/plugins/licensing/tsconfig.json b/x-pack/plugins/licensing/tsconfig.json index f726ed7c091239..8eed250935b339 100644 --- a/x-pack/plugins/licensing/tsconfig.json +++ b/x-pack/plugins/licensing/tsconfig.json @@ -12,9 +12,9 @@ "@kbn/config-schema", "@kbn/std", "@kbn/i18n", - "@kbn/analytics-client", "@kbn/logging-mocks", - "@kbn/react-kibana-mount" + "@kbn/react-kibana-mount", + "@kbn/ebt" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/apm/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/apm/public/services/telemetry/types.ts index 11a8a6f225f277..5592974de2d408 100644 --- a/x-pack/plugins/observability_solution/apm/public/services/telemetry/types.ts +++ b/x-pack/plugins/observability_solution/apm/public/services/telemetry/types.ts @@ -5,8 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; -import type { AnalyticsServiceSetup } from '@kbn/core/public'; +import type { AnalyticsServiceSetup, RootSchema } from '@kbn/core/public'; export interface TelemetryServiceSetupParams { analytics: AnalyticsServiceSetup; diff --git a/x-pack/plugins/observability_solution/apm/tsconfig.json b/x-pack/plugins/observability_solution/apm/tsconfig.json index 981980f93b92ea..c763acff6ea855 100644 --- a/x-pack/plugins/observability_solution/apm/tsconfig.json +++ b/x-pack/plugins/observability_solution/apm/tsconfig.json @@ -99,7 +99,6 @@ "@kbn/profiling-data-access-plugin", "@kbn/profiling-utils", "@kbn/core-analytics-server", - "@kbn/analytics-client", "@kbn/monaco", "@kbn/deeplinks-observability", "@kbn/custom-icons", diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts index 16bdb5658f7405..1ac068d5bb2312 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts @@ -5,8 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; -import type { AnalyticsServiceSetup } from '@kbn/core/public'; +import type { AnalyticsServiceSetup, RootSchema } from '@kbn/core/public'; export interface TelemetryServiceSetupParams { analytics: AnalyticsServiceSetup; diff --git a/x-pack/plugins/observability_solution/infra/tsconfig.json b/x-pack/plugins/observability_solution/infra/tsconfig.json index cb98f8ab0859e8..d1d1f0542da0a1 100644 --- a/x-pack/plugins/observability_solution/infra/tsconfig.json +++ b/x-pack/plugins/observability_solution/infra/tsconfig.json @@ -56,7 +56,6 @@ "@kbn/charts-plugin", "@kbn/lens-plugin", "@kbn/core-analytics-server", - "@kbn/analytics-client", "@kbn/shared-ux-router", "@kbn/alerts-as-data-utils", "@kbn/cases-plugin", diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/chat_feedback.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/chat_feedback.ts index fa0c670fa29880..01df60e95a952d 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/chat_feedback.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/chat_feedback.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { EventTypeOpts } from '@kbn/analytics-client'; +import type { EventTypeOpts } from '@kbn/core/public'; import type { Message, Conversation } from '../../../common'; import type { Feedback } from '../../components/buttons/feedback_buttons'; import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type'; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/common.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/common.ts index 3c4d4ee0c75e00..b01a8e05a4ea57 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/common.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/common.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/core/public'; import type { Message } from '../../../common'; export const messageSchema: RootSchema = { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_feedback.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_feedback.ts index 7f8a37cf95aeed..67bd03f1fcd4f3 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_feedback.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_feedback.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { EventTypeOpts } from '@kbn/analytics-client'; +import type { EventTypeOpts } from '@kbn/core/public'; import type { Message } from '../../../common'; import type { Feedback } from '../../components/buttons/feedback_buttons'; import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type'; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/user_sent_prompt.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/user_sent_prompt.ts index b7ce5f2dacb381..9c6f6d45110b13 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/user_sent_prompt.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/user_sent_prompt.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { EventTypeOpts } from '@kbn/analytics-client'; +import type { EventTypeOpts } from '@kbn/core/public'; import type { Message } from '../../../common'; import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type'; import { messageSchema } from './common'; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/analytics/recall_ranking.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/analytics/recall_ranking.ts index 8a6f6a88d85387..ab6201780038a3 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/analytics/recall_ranking.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/analytics/recall_ranking.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RootSchema, EventTypeOpts } from '@kbn/analytics-client'; +import { RootSchema, EventTypeOpts } from '@kbn/core/public'; interface ScoredDocument { content: string; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json b/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json index 0db746a4ab80c7..aa26acbb6154a7 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json @@ -15,7 +15,6 @@ "kbn_references": [ "@kbn/i18n", "@kbn/core-analytics-browser", - "@kbn/analytics-client", "@kbn/logging", "@kbn/core", "@kbn/server-route-repository", diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/common/telemetry_events.ts b/x-pack/plugins/observability_solution/observability_logs_explorer/common/telemetry_events.ts index 3d8b6ce58f3f39..8776d2fd44dbb4 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/common/telemetry_events.ts +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/common/telemetry_events.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { type EventTypeOpts } from '@kbn/analytics-client'; +import { type EventTypeOpts } from '@kbn/ebt/client'; export const DATA_RECEIVED_TELEMETRY_EVENT: EventTypeOpts<{ rowCount: number; diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/tsconfig.json b/x-pack/plugins/observability_solution/observability_logs_explorer/tsconfig.json index a3b20757c0096d..446c237e257eb1 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/tsconfig.json @@ -47,10 +47,10 @@ "@kbn/shared-ux-prompt-not-found", "@kbn/slo-plugin", "@kbn/es-query", - "@kbn/analytics-client", "@kbn/core-analytics-browser", "@kbn/react-hooks", "@kbn/data-quality-plugin", + "@kbn/ebt", ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_solution/observability_onboarding/common/telemetry_events.ts b/x-pack/plugins/observability_solution/observability_onboarding/common/telemetry_events.ts index 24a4167d257c73..998c3e9cc91227 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/common/telemetry_events.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/common/telemetry_events.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { type EventTypeOpts } from '@kbn/analytics-client'; +import { type EventTypeOpts } from '@kbn/ebt/client'; export const OBSERVABILITY_ONBOARDING_TELEMETRY_EVENT: EventTypeOpts<{ flow?: string; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json b/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json index eb31601928b877..947a1230afd164 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json @@ -36,9 +36,9 @@ "@kbn/shared-ux-link-redirect-app", "@kbn/cloud-experiments-plugin", "@kbn/home-sample-data-tab", - "@kbn/analytics-client", "@kbn/react-kibana-context-render", - "@kbn/react-kibana-context-theme" + "@kbn/react-kibana-context-theme", + "@kbn/ebt" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/reporting/server/usage/register_event_types.ts b/x-pack/plugins/reporting/server/usage/register_event_types.ts index bf34d33cf37c7e..6347443eee8f7c 100644 --- a/x-pack/plugins/reporting/server/usage/register_event_types.ts +++ b/x-pack/plugins/reporting/server/usage/register_event_types.ts @@ -5,9 +5,7 @@ * 2.0. */ -import { RootSchema } from '@kbn/analytics-client'; -import { EventTypeOpts } from '@kbn/core/public'; -import type { CoreSetup } from '@kbn/core/server'; +import type { CoreSetup, EventTypeOpts, RootSchema } from '@kbn/core/server'; import { EventType, FieldType } from '@kbn/reporting-server'; const fields: Record>> = { diff --git a/x-pack/plugins/reporting/tsconfig.json b/x-pack/plugins/reporting/tsconfig.json index e0f781d28f62cc..b52c02a72bed16 100644 --- a/x-pack/plugins/reporting/tsconfig.json +++ b/x-pack/plugins/reporting/tsconfig.json @@ -47,7 +47,6 @@ "@kbn/reporting-mocks-server", "@kbn/core-http-request-handler-context-server", "@kbn/reporting-public", - "@kbn/analytics-client", "@kbn/reporting-csv-share-panel", "@kbn/react-kibana-context-render", "@kbn/react-kibana-mount", diff --git a/x-pack/plugins/search_playground/server/analytics/events.ts b/x-pack/plugins/search_playground/server/analytics/events.ts index 4330cb1a9e7956..0db146a2f45a52 100644 --- a/x-pack/plugins/search_playground/server/analytics/events.ts +++ b/x-pack/plugins/search_playground/server/analytics/events.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { EventTypeOpts } from '@kbn/analytics-client'; +import { EventTypeOpts } from '@kbn/core/server'; export interface SendMessageEventData { connectorType: string; diff --git a/x-pack/plugins/search_playground/tsconfig.json b/x-pack/plugins/search_playground/tsconfig.json index c75c9213103bf6..7e7217975cc85a 100644 --- a/x-pack/plugins/search_playground/tsconfig.json +++ b/x-pack/plugins/search_playground/tsconfig.json @@ -39,7 +39,6 @@ "@kbn/core-logging-server-mocks", "@kbn/analytics", "@kbn/usage-collection-plugin", - "@kbn/analytics-client", "@kbn/console-plugin" ], "exclude": [ diff --git a/x-pack/plugins/security/server/analytics/analytics_service.ts b/x-pack/plugins/security/server/analytics/analytics_service.ts index 98d316d8a8d5f7..b5bbbf0079cf98 100644 --- a/x-pack/plugins/security/server/analytics/analytics_service.ts +++ b/x-pack/plugins/security/server/analytics/analytics_service.ts @@ -5,8 +5,11 @@ * 2.0. */ -import type { EventTypeOpts } from '@kbn/analytics-client'; -import type { AnalyticsServiceSetup as CoreAnalyticsServiceSetup, Logger } from '@kbn/core/server'; +import type { + AnalyticsServiceSetup as CoreAnalyticsServiceSetup, + EventTypeOpts, + Logger, +} from '@kbn/core/server'; import type { CSPViolationReport, diff --git a/x-pack/plugins/security/tsconfig.json b/x-pack/plugins/security/tsconfig.json index f3ccbabffff97f..a555c58c5804ec 100644 --- a/x-pack/plugins/security/tsconfig.json +++ b/x-pack/plugins/security/tsconfig.json @@ -65,7 +65,6 @@ "@kbn/core-http-server", "@kbn/core-http-server-mocks", "@kbn/remote-clusters-plugin", - "@kbn/analytics-client", "@kbn/security-plugin-types-common", "@kbn/security-plugin-types-public", "@kbn/security-plugin-types-server", diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/ai_assistant/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/ai_assistant/types.ts index 87dbb38b4b5c7d..54a9660d3b2d8e 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/ai_assistant/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/ai_assistant/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/core/public'; import type { TelemetryEventTypes } from '../../constants'; export interface ReportAssistantInvokedParams { diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/types.ts index cc654e532f88d7..d2b5e227ee66ac 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/core/public'; import type { TelemetryEventTypes } from '../../constants'; export interface ReportAlertsGroupingChangedParams { diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/attack_discovery/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/attack_discovery/types.ts index e76813d280bc00..dc83083bd38e3e 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/attack_discovery/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/attack_discovery/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/core/public'; import type { TelemetryEventTypes } from '../../constants'; export interface ReportAttackDiscoveriesGeneratedParams { diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/types.ts index 2b31e6cefea4f5..9e1d012811e3be 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/core/public'; import type { TelemetryEventTypes } from '../../constants'; export type ReportDataQualityIndexCheckedParams = ReportDataQualityCheckAllCompletedParams & { diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/types.ts index a090686c91267c..7a3ff374eae3cd 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/core/public'; import type { TelemetryEventTypes } from '../../constants'; export interface ReportDetailsFlyoutOpenedParams { diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts index 9d38694324e55b..d71c48004d756f 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/core/public'; import type { RiskSeverity } from '../../../../../../common/search_strategy'; import type { TelemetryEventTypes } from '../../constants'; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/types.ts index 51ceefb49d5be3..f6f52a6d675d27 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/types.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; +import type { RootSchema } from '@kbn/core/public'; import type { StepLinkId } from '../../../../components/landing_page/onboarding/step_links/types'; import type { TelemetryEventTypes } from '../../constants'; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts index e42c2cd8ab23cc..3be54678c0ad82 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts @@ -5,8 +5,7 @@ * 2.0. */ -import type { RootSchema } from '@kbn/analytics-client'; -import type { AnalyticsServiceSetup } from '@kbn/core/public'; +import type { AnalyticsServiceSetup, RootSchema } from '@kbn/core/public'; import type { AttackDiscoveryTelemetryEvent, ReportAttackDiscoveriesGeneratedParams, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx index 0a8fdcbaacd87d..1edb154db295c5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx @@ -84,7 +84,7 @@ const useIsExperimentalFeatureEnabledMock = jest.fn((feature: keyof Experimental jest.mock('../../../../../common/lib/kibana'); // unified-field-list is reporting multiple analytics events -jest.mock(`@kbn/analytics-client`); +jest.mock(`@kbn/ebt/client`); const TestComponent = (props: Partial>) => { const testComponentDefaultProps: ComponentProps = { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx index bca35ae0af4461..4cb56cdeba0128 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx @@ -75,8 +75,8 @@ const useIsExperimentalFeatureEnabledMock = jest.fn((feature: keyof Experimental jest.mock('../../../../common/lib/kibana'); -// unified-field-list is is reporiting multiple analytics events -jest.mock(`@kbn/analytics-client`); +// unified-field-list is reporting multiple analytics events +jest.mock(`@kbn/ebt/client`); const columnsToDisplay = [ ...defaultUdtHeaders, diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts b/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts index af165617bf37c7..03552f02e39cfb 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { EventTypeOpts } from '@kbn/analytics-client'; +import type { EventTypeOpts } from '@kbn/core/server'; import type { AssetCriticalityCsvUploadResponse } from '../../../../common/api/entity_analytics'; export const RISK_SCORE_EXECUTION_SUCCESS_EVENT: EventTypeOpts<{ diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 610a76cd6f5ee6..f1320dc3205be2 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -149,7 +149,6 @@ "@kbn/grouping", "@kbn/securitysolution-data-table", "@kbn/core-analytics-server", - "@kbn/analytics-client", "@kbn/security-solution-side-nav", "@kbn/ml-anomaly-utils", "@kbn/discover-plugin", diff --git a/x-pack/plugins/security_solution_serverless/server/telemetry/event_based_telemetry.ts b/x-pack/plugins/security_solution_serverless/server/telemetry/event_based_telemetry.ts index 919338437643f6..578b37f389cb39 100644 --- a/x-pack/plugins/security_solution_serverless/server/telemetry/event_based_telemetry.ts +++ b/x-pack/plugins/security_solution_serverless/server/telemetry/event_based_telemetry.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { EventTypeOpts } from '@kbn/analytics-client'; +import type { EventTypeOpts } from '@kbn/core/server'; export const NLP_CLEANUP_TASK_EVENT: EventTypeOpts<{ failedToDeleteCount: number; diff --git a/x-pack/plugins/security_solution_serverless/tsconfig.json b/x-pack/plugins/security_solution_serverless/tsconfig.json index 5cf1fcc8431a42..a1c6cefd396ca8 100644 --- a/x-pack/plugins/security_solution_serverless/tsconfig.json +++ b/x-pack/plugins/security_solution_serverless/tsconfig.json @@ -44,6 +44,5 @@ "@kbn/management-cards-navigation", "@kbn/discover-plugin", "@kbn/logging", - "@kbn/analytics-client", ] } diff --git a/yarn.lock b/yarn.lock index 463d1d469c7b14..834ac4b0583564 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3277,10 +3277,6 @@ version "0.0.0" uid "" -"@kbn/analytics-client@link:packages/analytics/client": - version "0.0.0" - uid "" - "@kbn/analytics-collection-utils@link:packages/analytics/utils/analytics_collection_utils": version "0.0.0" uid "" @@ -3293,22 +3289,6 @@ version "0.0.0" uid "" -"@kbn/analytics-shippers-elastic-v3-browser@link:packages/analytics/shippers/elastic_v3/browser": - version "0.0.0" - uid "" - -"@kbn/analytics-shippers-elastic-v3-common@link:packages/analytics/shippers/elastic_v3/common": - version "0.0.0" - uid "" - -"@kbn/analytics-shippers-elastic-v3-server@link:packages/analytics/shippers/elastic_v3/server": - version "0.0.0" - uid "" - -"@kbn/analytics-shippers-fullstory@link:packages/analytics/shippers/fullstory": - version "0.0.0" - uid "" - "@kbn/analytics@link:packages/kbn-analytics": version "0.0.0" uid "" @@ -4657,6 +4637,10 @@ version "0.0.0" uid "" +"@kbn/ebt@link:packages/analytics/ebt": + version "0.0.0" + uid "" + "@kbn/ecs-data-quality-dashboard-plugin@link:x-pack/plugins/ecs_data_quality_dashboard": version "0.0.0" uid "" From e06ee80f86f159b89db3dea40e1f3924cb2e7df9 Mon Sep 17 00:00:00 2001 From: Drew Tate Date: Tue, 18 Jun 2024 06:38:42 -0600 Subject: [PATCH 025/123] [ES|QL] validate inline casting (#185904) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Adds basic validation for inline casting. To do this I had to create a new type of AST node and update the validation logic. I sort of snuck in a refactor of our column checking logic as well. It just kind of happened 🤷‍♂️ Check out the validation tests for some good cases: https://github.com/elastic/kibana/pull/185904/files#diff-89c4af0faedcf80d51cfb19ae397a5898c7293055b19284a94cb3f6a7cd4d071R1948 ### Not covered yet One thing this doesn't cover is that some casts only work for some types of data. For example `123::cartesian_point` won't work... the value has to be a string. This is because `123::cartesian_point` is actually syntactic sugar for `to_cartesianpoint(123)`. In https://github.com/elastic/elasticsearch/pull/109713 Nik is giving us a table of the casts to their functions so that we can derive this data and be a bit more accurate. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Stratoula Kalafateli Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../__tests__/ast_parser.inlinecast.test.ts | 67 +++++ packages/kbn-esql-ast/src/ast_helpers.ts | 39 ++- packages/kbn-esql-ast/src/ast_walker.ts | 26 +- packages/kbn-esql-ast/src/types.ts | 25 +- .../kbn-esql-validation-autocomplete/index.ts | 5 +- .../scripts/generate_function_definitions.ts | 35 +-- .../src/autocomplete/autocomplete.test.ts | 4 +- .../src/autocomplete/autocomplete.ts | 23 +- .../src/definitions/options.ts | 5 +- .../src/definitions/types.ts | 2 +- .../src/shared/esql_to_kibana_type.ts | 44 ++++ .../src/shared/helpers.ts | 96 ++++--- .../esql_validation_meta_tests.json | 126 ++++++++++ .../src/validation/validation.test.ts | 63 +++++ .../src/validation/validation.ts | 235 +++++++++++------- 15 files changed, 611 insertions(+), 184 deletions(-) create mode 100644 packages/kbn-esql-ast/src/__tests__/ast_parser.inlinecast.test.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/shared/esql_to_kibana_type.ts diff --git a/packages/kbn-esql-ast/src/__tests__/ast_parser.inlinecast.test.ts b/packages/kbn-esql-ast/src/__tests__/ast_parser.inlinecast.test.ts new file mode 100644 index 00000000000000..3f45f55b549da6 --- /dev/null +++ b/packages/kbn-esql-ast/src/__tests__/ast_parser.inlinecast.test.ts @@ -0,0 +1,67 @@ +/* + * 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 { getAstAndSyntaxErrors as parse } from '../ast_parser'; +import { ESQLFunction, ESQLInlineCast, ESQLSingleAstItem } from '../types'; + +describe('Inline cast (::)', () => { + describe('correctly formatted', () => { + it('can be a command argument', () => { + const text = 'FROM kibana_ecommerce_data | EVAL field::string'; + const { ast, errors } = parse(text); + + expect(errors.length).toBe(0); + expect(ast[1].args[0]).toEqual( + expect.objectContaining({ + castType: 'string', + name: 'inlineCast', + type: 'inlineCast', + value: expect.objectContaining({ + name: 'field', + type: 'column', + }), + }) + ); + }); + + it('can be a function argument', () => { + const text = 'FROM kibana_ecommerce_data | EVAL round(field::long)'; + const { ast, errors } = parse(text); + + expect(errors.length).toBe(0); + expect((ast[1].args[0] as ESQLFunction).args[0]).toEqual( + expect.objectContaining({ + castType: 'long', + name: 'inlineCast', + type: 'inlineCast', + value: expect.objectContaining({ + name: 'field', + type: 'column', + }), + }) + ); + }); + + it('can be nested', () => { + const text = 'FROM kibana_ecommerce_data | EVAL field::long::string::datetime'; + const { ast, errors } = parse(text); + + expect(errors.length).toBe(0); + let currentNode = ast[1].args[0]; + let depth = 0; + + while (depth < 3) { + expect((currentNode as ESQLSingleAstItem).type).toBe('inlineCast'); + currentNode = (currentNode as ESQLInlineCast).value; + depth++; + } + + expect((currentNode as ESQLSingleAstItem).name).toBe('field'); + }); + }); +}); diff --git a/packages/kbn-esql-ast/src/ast_helpers.ts b/packages/kbn-esql-ast/src/ast_helpers.ts index ae97040ecaaf17..69ea76c091146e 100644 --- a/packages/kbn-esql-ast/src/ast_helpers.ts +++ b/packages/kbn-esql-ast/src/ast_helpers.ts @@ -14,6 +14,7 @@ import { type Token, type ParserRuleContext, type TerminalNode } from 'antlr4'; import type { ArithmeticUnaryContext, DecimalValueContext, + InlineCastContext, IntegerValueContext, QualifiedIntegerLiteralContext, } from './antlr/esql_parser'; @@ -32,6 +33,8 @@ import type { ESQLCommandOption, ESQLAstItem, ESQLCommandMode, + ESQLInlineCast, + ESQLUnknownItem, } from './types'; export function nonNullable(v: T): v is NonNullable { @@ -61,6 +64,17 @@ export function createCommand(name: string, ctx: ParserRuleContext): ESQLCommand }; } +export function createInlineCast(ctx: InlineCastContext): Omit { + return { + type: 'inlineCast', + name: 'inlineCast', + text: ctx.getText(), + castType: ctx.dataType().getText(), + location: getPosition(ctx.start, ctx.stop), + incomplete: Boolean(ctx.exception), + }; +} + export function createList(ctx: ParserRuleContext, values: ESQLLiteral[]): ESQLList { return { type: 'list', @@ -120,11 +134,20 @@ export function textExistsAndIsValid(text: string | undefined): text is string { export function createLiteral( type: ESQLLiteral['literalType'], - node: TerminalNode | undefined -): ESQLLiteral | undefined { + node: TerminalNode | null +): ESQLLiteral { if (!node) { - return; + return { + type: 'literal', + name: 'unknown', + text: 'unknown', + value: 'unknown', + literalType: type, + location: { min: 0, max: 0 }, + incomplete: false, + } as ESQLLiteral; } + const text = node.getText(); const partialLiteral: Omit = { @@ -347,3 +370,13 @@ export function createOption(name: string, ctx: ParserRuleContext): ESQLCommandO ), }; } + +export function createUnknownItem(ctx: ParserRuleContext): ESQLUnknownItem { + return { + type: 'unknown', + name: 'unknown', + text: ctx.getText(), + location: getPosition(ctx.start, ctx.stop), + incomplete: Boolean(ctx.exception), + }; +} diff --git a/packages/kbn-esql-ast/src/ast_walker.ts b/packages/kbn-esql-ast/src/ast_walker.ts index 064b1b7d3126e4..fc47227a0b0ed8 100644 --- a/packages/kbn-esql-ast/src/ast_walker.ts +++ b/packages/kbn-esql-ast/src/ast_walker.ts @@ -57,6 +57,7 @@ import { type ValueExpressionContext, ValueExpressionDefaultContext, IndexIdentifierContext, + InlineCastContext, } from './antlr/esql_parser'; import { createSource, @@ -76,6 +77,8 @@ import { createPolicy, createSetting, textExistsAndIsValid, + createInlineCast, + createUnknownItem, } from './ast_helpers'; import { getPosition } from './ast_position_utils'; import type { @@ -84,6 +87,7 @@ import type { ESQLFunction, ESQLCommandOption, ESQLAstItem, + ESQLInlineCast, } from './types'; export function collectAllSourceIdentifiers(ctx: FromCommandContext): ESQLAstItem[] { @@ -292,7 +296,7 @@ function getBooleanValue(ctx: BooleanLiteralContext | BooleanValueContext) { return createLiteral('boolean', booleanTerminalNode!); } -function getConstant(ctx: ConstantContext | undefined): ESQLAstItem | undefined { +function getConstant(ctx: ConstantContext): ESQLAstItem { if (ctx instanceof NullLiteralContext) { return createLiteral('null', ctx.NULL()); } @@ -334,6 +338,8 @@ function getConstant(ctx: ConstantContext | undefined): ESQLAstItem | undefined } return createList(ctx, values); } + + return createUnknownItem(ctx); } export function visitRenameClauses(clausesCtx: RenameClauseContext[]): ESQLAstItem[] { @@ -355,9 +361,7 @@ export function visitRenameClauses(clausesCtx: RenameClauseContext[]): ESQLAstIt .filter(nonNullable); } -export function visitPrimaryExpression( - ctx: PrimaryExpressionContext -): ESQLAstItem | ESQLAstItem[] | undefined { +export function visitPrimaryExpression(ctx: PrimaryExpressionContext): ESQLAstItem | ESQLAstItem[] { if (ctx instanceof ConstantDefaultContext) { return getConstant(ctx.constant()); } @@ -385,6 +389,18 @@ export function visitPrimaryExpression( } return fn; } + if (ctx instanceof InlineCastContext) { + return collectInlineCast(ctx); + } + return createUnknownItem(ctx); +} + +function collectInlineCast(ctx: InlineCastContext): ESQLInlineCast { + const primaryExpression = visitPrimaryExpression(ctx.primaryExpression()); + return { + ...createInlineCast(ctx), + value: primaryExpression, + }; } export function collectLogicalExpression(ctx: BooleanExpressionContext) { @@ -512,7 +528,7 @@ export function visitOrderExpression(ctx: OrderExpressionContext[]) { } if (orderCtx.NULLS()) { expression.push(createLiteral('string', orderCtx.NULLS()!)!); - if (orderCtx._nullOrdering) { + if (orderCtx._nullOrdering && orderCtx._nullOrdering.text !== '') { const innerTerminalNode = orderCtx.getToken(esql_parser.FIRST, 0) || orderCtx.getToken(esql_parser.LAST, 0); const literal = createLiteral('string', innerTerminalNode); diff --git a/packages/kbn-esql-ast/src/types.ts b/packages/kbn-esql-ast/src/types.ts index 927ab619abfed6..22a53d6368d9d5 100644 --- a/packages/kbn-esql-ast/src/types.ts +++ b/packages/kbn-esql-ast/src/types.ts @@ -18,7 +18,9 @@ export type ESQLSingleAstItem = | ESQLTimeInterval | ESQLList | ESQLLiteral - | ESQLCommandMode; + | ESQLCommandMode + | ESQLInlineCast + | ESQLUnknownItem; export type ESQLAstItem = ESQLSingleAstItem | ESQLAstItem[]; @@ -59,6 +61,27 @@ export interface ESQLFunction extends ESQLAstBaseItem { args: ESQLAstItem[]; } +export interface ESQLInlineCast extends ESQLAstBaseItem { + type: 'inlineCast'; + value: ValueType; + castType: string; +} + +/** + * This node represents something the AST generator + * didn't recognize in the ANTLR parse tree. + * + * It can show up if the AST generator code is out of sync + * with the ANTLR grammar or if there is some idiosyncrasy + * or bug in the parse tree. + * + * These nodes can be ignored for the purpose of validation + * and autocomplete, but they may be helpful in detecting bugs. + */ +export interface ESQLUnknownItem extends ESQLAstBaseItem { + type: 'unknown'; +} + export interface ESQLTimeInterval extends ESQLAstBaseItem { type: 'timeInterval'; unit: string; diff --git a/packages/kbn-esql-validation-autocomplete/index.ts b/packages/kbn-esql-validation-autocomplete/index.ts index d4c4420ffeca43..31bd8c16b76fba 100644 --- a/packages/kbn-esql-validation-autocomplete/index.ts +++ b/packages/kbn-esql-validation-autocomplete/index.ts @@ -49,11 +49,10 @@ export { getCommandDefinition, getAllCommands, getCommandOption, - getColumnHit, - columnExists, + lookupColumn, shouldBeQuotedText, printFunctionSignature, - isEqualType, + checkFunctionArgMatchesDefinition as isEqualType, isSourceItem, isSettingItem, isFunctionItem, diff --git a/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts b/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts index 15333c62300fae..ad9966defd9cb2 100644 --- a/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts +++ b/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts @@ -12,6 +12,7 @@ import { join } from 'path'; import _ from 'lodash'; import type { RecursivePartial } from '@kbn/utility-types'; import { FunctionDefinition } from '../src/definitions/types'; +import { esqlToKibanaType } from '../src/shared/esql_to_kibana_type'; const aliasTable: Record = { to_version: ['to_ver'], @@ -56,36 +57,6 @@ const extraFunctions: FunctionDefinition[] = [ }, ]; -const elasticsearchToKibanaType = (elasticsearchType: string) => { - if ( - [ - 'double', - 'unsigned_long', - 'long', - 'integer', - 'counter_integer', - 'counter_long', - 'counter_double', - ].includes(elasticsearchType) - ) { - return 'number'; - } - - if (['text', 'keyword'].includes(elasticsearchType)) { - return 'string'; - } - - if (['datetime', 'time_duration'].includes(elasticsearchType)) { - return 'date'; - } - - if (elasticsearchType === 'date_period') { - return 'time_literal'; // TODO - consider aligning with Elasticsearch - } - - return elasticsearchType; -}; - const validateLogFunctions = `(fnDef: ESQLFunction) => { const messages = []; // do not really care here about the base and field @@ -237,10 +208,10 @@ function getFunctionDefinition(ESFunctionDefinition: Record): Funct ...signature, params: signature.params.map((param: any) => ({ ...param, - type: elasticsearchToKibanaType(param.type), + type: esqlToKibanaType(param.type), description: undefined, })), - returnType: elasticsearchToKibanaType(signature.returnType), + returnType: esqlToKibanaType(signature.returnType), variadic: undefined, // we don't support variadic property minParams: signature.variadic ? signature.params.filter((param: any) => !param.optional).length diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts index 528e5f338b53e3..828511762a5f40 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts @@ -16,7 +16,7 @@ import { getUnitDuration, TRIGGER_SUGGESTION_COMMAND } from './factories'; import { camelCase, partition } from 'lodash'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; import { groupingFunctionDefinitions } from '../definitions/grouping'; -import { FunctionArgSignature } from '../definitions/types'; +import { FunctionParameter } from '../definitions/types'; import { getParamAtPosition } from './helper'; import { nonNullable } from '../shared/helpers'; import { METADATA_FIELDS } from '../shared/constants'; @@ -1182,7 +1182,7 @@ describe('autocomplete', () => { (p) => p.constantOnly || /_literal/.test(p.type) ); - const getTypesFromParamDefs = (paramDefs: FunctionArgSignature[]) => + const getTypesFromParamDefs = (paramDefs: FunctionParameter[]) => Array.from(new Set(paramDefs.map((p) => p.type))); const suggestedConstants = param.literalSuggestions || param.literalOptions; diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index ba2f180fb51f61..727335fe6d9613 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -18,8 +18,7 @@ import type { import { partition } from 'lodash'; import type { EditorContext, SuggestionRawDefinition } from './types'; import { - columnExists, - getColumnHit, + lookupColumn, getCommandDefinition, getCommandOption, getFunctionDefinition, @@ -42,6 +41,7 @@ import { getAllFunctions, isSingleItem, nonNullable, + getColumnExists, } from '../shared/helpers'; import { collectVariables, excludeVariablesFromCurrentCommand } from '../shared/variables'; import type { ESQLPolicy, ESQLRealField, ESQLVariable, ReferenceMaps } from '../validation/types'; @@ -87,7 +87,7 @@ import { getSourcesFromCommands, isAggFunctionUsedAlready, } from './helper'; -import { FunctionArgSignature } from '../definitions/types'; +import { FunctionParameter } from '../definitions/types'; type GetSourceFn = () => Promise; type GetDataSourceFn = (sourceName: string) => Promise< @@ -345,7 +345,9 @@ function workoutBuiltinOptions( references: Pick ): { skipAssign: boolean } { // skip assign operator if it's a function or an existing field to avoid promoting shadowing - return { skipAssign: Boolean(!isColumnItem(nodeArg) || getColumnHit(nodeArg.name, references)) }; + return { + skipAssign: Boolean(!isColumnItem(nodeArg) || lookupColumn(nodeArg, references)), + }; } function areCurrentArgsValid( @@ -412,7 +414,7 @@ function extractFinalTypeFromArg( return arg.literalType; } if (isColumnItem(arg)) { - const hit = getColumnHit(arg.name, references); + const hit = lookupColumn(arg, references); if (hit) { return hit.type; } @@ -1166,10 +1168,10 @@ async function getFunctionArgsSuggestions( const isUnknownColumn = arg && isColumnItem(arg) && - !columnExists(arg, { + !getColumnExists(arg, { fields: fieldsMap, variables: variablesExcludingCurrentCommandOnes, - }).hit; + }); if (noArgDefined || isUnknownColumn) { // ... | EVAL fn( ) // ... | EVAL fn( field, ) @@ -1243,7 +1245,7 @@ async function getFunctionArgsSuggestions( (paramDef) => paramDef.constantOnly || /_literal$/.test(paramDef.type) ); - const getTypesFromParamDefs = (paramDefs: FunctionArgSignature[]) => { + const getTypesFromParamDefs = (paramDefs: FunctionParameter[]) => { return Array.from(new Set(paramDefs.map(({ type }) => type))); }; @@ -1517,7 +1519,10 @@ async function getOptionArgsSuggestions( } if (command.name === 'dissect') { - if (option.args.length < 1 && optionDef) { + if ( + option.args.filter((arg) => !(isSingleItem(arg) && arg.type === 'unknown')).length < 1 && + optionDef + ) { suggestions.push(colonCompleteItem, semiColonCompleteItem); } } diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts index 8e30a43db2c8fa..13e3ea66ef1063 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import type { ESQLCommandOption, ESQLMessage } from '@kbn/esql-ast'; -import { isLiteralItem, isColumnItem } from '../shared/helpers'; +import { isLiteralItem, isColumnItem, isInlineCastItem } from '../shared/helpers'; import { getMessageFromId } from '../validation/errors'; import type { CommandOptionsDefinition } from './types'; @@ -130,7 +130,8 @@ export const appendSeparatorOption: CommandOptionsDefinition = { !Array.isArray(firstArg) && (!isLiteralItem(firstArg) || firstArg.literalType !== 'string') ) { - const value = 'value' in firstArg ? firstArg.value : firstArg.name; + const value = + 'value' in firstArg && !isInlineCastItem(firstArg) ? firstArg.value : firstArg.name; messages.push( getMessageFromId({ messageId: 'wrongDissectOptionArgumentType', diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts index dbfbf08cca08ae..05adb6eed58361 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts @@ -158,4 +158,4 @@ export type SignatureType = | CommandOptionsDefinition['signature']; export type SignatureArgType = SignatureType['params'][number]; -export type FunctionArgSignature = FunctionDefinition['signatures'][number]['params'][number]; +export type FunctionParameter = FunctionDefinition['signatures'][number]['params'][number]; diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/esql_to_kibana_type.ts b/packages/kbn-esql-validation-autocomplete/src/shared/esql_to_kibana_type.ts new file mode 100644 index 00000000000000..f13052288f29fb --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/shared/esql_to_kibana_type.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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. + */ + +const ESQL_NUMBER_TYPES = [ + 'double', + 'unsigned_long', + 'long', + 'integer', + 'int', + 'counter_integer', + 'counter_long', + 'counter_double', +]; + +const ESQL_TEXT_TYPES = ['text', 'keyword', 'string']; + +export const esqlToKibanaType = (elasticsearchType: string) => { + if (ESQL_NUMBER_TYPES.includes(elasticsearchType)) { + return 'number'; + } + + if (ESQL_TEXT_TYPES.includes(elasticsearchType)) { + return 'string'; + } + + if (['datetime', 'time_duration'].includes(elasticsearchType)) { + return 'date'; + } + + if (elasticsearchType === 'bool') { + return 'boolean'; + } + + if (elasticsearchType === 'date_period') { + return 'time_literal'; // TODO - consider aligning with Elasticsearch + } + + return elasticsearchType; +}; diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts index 348a9b45e5d12e..201b7bf045d0f2 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts @@ -17,6 +17,7 @@ import type { ESQLSource, ESQLTimeInterval, } from '@kbn/esql-ast'; +import { ESQLInlineCast } from '@kbn/esql-ast/src/types'; import { statsAggregationFunctionDefinitions } from '../definitions/aggs'; import { builtinFunctions } from '../definitions/builtin'; import { commandDefinitions } from '../definitions/commands'; @@ -35,14 +36,14 @@ import { import type { CommandDefinition, CommandOptionsDefinition, - FunctionArgSignature, + FunctionParameter, FunctionDefinition, FunctionParameterType, FunctionReturnType, - SignatureArgType, } from '../definitions/types'; import type { ESQLRealField, ESQLVariable, ReferenceMaps } from '../validation/types'; import { removeMarkerArgFromArgsList } from './context'; +import { esqlToKibanaType } from './esql_to_kibana_type'; import type { ReasonTypes } from './types'; export function nonNullable(v: T): v is NonNullable { @@ -76,6 +77,10 @@ export function isLiteralItem(arg: ESQLAstItem): arg is ESQLLiteral { return isSingleItem(arg) && arg.type === 'literal'; } +export function isInlineCastItem(arg: ESQLAstItem): arg is ESQLInlineCast { + return isSingleItem(arg) && arg.type === 'inlineCast'; +} + export function isTimeIntervalItem(arg: ESQLAstItem): arg is ESQLTimeInterval { return isSingleItem(arg) && arg.type === 'timeInterval'; } @@ -235,11 +240,14 @@ function compareLiteralType(argType: string, item: ESQLLiteral) { return ['string', 'date'].includes(argType); } -export function getColumnHit( - columnName: string, - { fields, variables }: Pick, - position?: number +/** + * This function returns the variable or field matching a column + */ +export function lookupColumn( + column: ESQLColumn, + { fields, variables }: Pick ): ESQLRealField | ESQLVariable | undefined { + const columnName = getQuotedColumnName(column); return fields.get(columnName) || variables.get(columnName)?.[0]; } @@ -350,7 +358,7 @@ export function getAllArrayTypes( types.push(subArg.literalType); } if (subArg.type === 'column') { - const hit = getColumnHit(subArg.name, references); + const hit = lookupColumn(subArg, references); types.push(hit?.type || 'unsupported'); } if (subArg.type === 'timeInterval') { @@ -377,7 +385,7 @@ export function inKnownTimeInterval(item: ESQLTimeInterval): boolean { * * TODO - Consider merging with isEqualType to create a unified arg validation function */ -export function isValidLiteralOption(arg: ESQLLiteral, argDef: FunctionArgSignature) { +export function isValidLiteralOption(arg: ESQLLiteral, argDef: FunctionParameter) { return ( arg.literalType === 'string' && argDef.literalOptions && @@ -388,17 +396,16 @@ export function isValidLiteralOption(arg: ESQLLiteral, argDef: FunctionArgSignat } /** - * Checks if an AST argument is of the correct type + * Checks if an AST function argument is of the correct type * given the definition. */ -export function isEqualType( +export function checkFunctionArgMatchesDefinition( arg: ESQLSingleAstItem, - argDef: SignatureArgType, + parameterDefinition: FunctionParameter, references: ReferenceMaps, - parentCommand?: string, - nameHit?: string + parentCommand?: string ) { - const argType = 'innerType' in argDef && argDef.innerType ? argDef.innerType : argDef.type; + const argType = parameterDefinition.type; if (argType === 'any') { return true; } @@ -417,11 +424,7 @@ export function isEqualType( return argType === 'time_literal' && inKnownTimeInterval(arg); } if (arg.type === 'column') { - if (argType === 'column') { - // anything goes, so avoid any effort here - return true; - } - const hit = getColumnHit(nameHit ?? arg.name, references); + const hit = lookupColumn(arg, references); const validHit = hit; if (!validHit) { return false; @@ -430,6 +433,10 @@ export function isEqualType( // if final type is of type any make it pass for now return wrappedTypes.some((ct) => ['any', 'null'].includes(ct) || argType === ct); } + if (arg.type === 'inlineCast') { + // TODO - remove with https://github.com/elastic/kibana/issues/174710 + return argType === esqlToKibanaType(arg.castType); + } } function fuzzySearch(fuzzyName: string, resources: IterableIterator) { @@ -499,25 +506,48 @@ export function hasCCSSource(name: string) { return name.includes(':'); } -export function columnExists( +/** + * This will return the name without any quotes. + * + * E.g. "`bytes`" will become "bytes" + * + * @param column + * @returns + */ +export const getUnquotedColumnName = (column: ESQLColumn) => column.name; + +/** + * This returns the name with any quotes that were present. + * + * E.g. "`bytes`" will be "`bytes`" + * + * @param column + * @returns + */ +export const getQuotedColumnName = (column: ESQLColumn) => + column.quoted ? column.text : column.name; + +/** + * TODO - consider calling lookupColumn under the hood of this function. Seems like they should really do the same thing. + */ +export function getColumnExists( column: ESQLColumn, { fields, variables }: Pick ) { - if (fields.has(column.name) || variables.has(column.name)) { - return { hit: true, nameHit: column.name }; - } - if (column.quoted) { - const originalName = column.text; - if (variables.has(originalName)) { - return { hit: true, nameHit: originalName }; + const namesToCheck = [getUnquotedColumnName(column), getQuotedColumnName(column)]; + + for (const name of namesToCheck) { + if (fields.has(name) || variables.has(name)) { + return true; + } + + // TODO — I don't see this fuzzy searching in lookupColumn... should it be there? + if (Boolean(fuzzySearch(name, fields.keys()) || fuzzySearch(name, variables.keys()))) { + return true; } } - if ( - Boolean(fuzzySearch(column.name, fields.keys()) || fuzzySearch(column.name, variables.keys())) - ) { - return { hit: true, nameHit: column.name }; - } - return { hit: false }; + + return false; } export function sourceExists(index: string, sources: Set) { diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json index 0fc1b047700a26..ba80daea19780c 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json +++ b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json @@ -8943,6 +8943,132 @@ "error": [], "warning": [] }, + { + "query": "from a_index | eval 1::string", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval 1::foo", + "error": [ + "Invalid type [foo] for casting" + ], + "warning": [] + }, + { + "query": "from a_index | eval 1::string::long::double", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval trim(\"23\"::double)", + "error": [ + "Argument of [trim] must be [string], found value [\"23\"::double] type [double]" + ], + "warning": [] + }, + { + "query": "from a_index | eval trim(23::string)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval 1 + \"2\"::long", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval 1 + \"2\"", + "error": [ + "Argument of [+] must be [number], found value [\"2\"] type [string]" + ], + "warning": [] + }, + { + "query": "from a_index | eval trim(to_double(\"23\")::string::double::long::string::double)", + "error": [ + "Argument of [trim] must be [string], found value [to_double(\"23\")::string::double::long::string::double] type [double]" + ], + "warning": [] + }, + { + "query": "from a_index | eval CEIL(23::long)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval CEIL(23::unsigned_long)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval CEIL(23::int)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval CEIL(23::integer)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval CEIL(23::double)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval TRIM(23::string)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval TRIM(23::text)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval TRIM(23::keyword)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval true AND \"false\"::boolean", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval true AND \"false\"::bool", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval true AND \"false\"", + "error": [ + "Argument of [and] must be [boolean], found value [\"false\"] type [string]" + ], + "warning": [] + }, + { + "query": "from a_index | eval to_lower(trim(numberField)::string)", + "error": [ + "Argument of [trim] must be [string], found value [numberField] type [number]" + ], + "warning": [] + }, + { + "query": "from a_index | eval to_upper(trim(numberField)::string::string::string::string)", + "error": [ + "Argument of [trim] must be [string], found value [numberField] type [number]" + ], + "warning": [] + }, + { + "query": "from a_index | eval to_lower(to_upper(trim(numberField)::string)::string)", + "error": [ + "Argument of [trim] must be [string], found value [numberField] type [number]" + ], + "warning": [] + }, { "query": "row var = date_diff(\"month\", \"2023-12-02T11:00:00.000Z\", \"2023-12-02T11:00:00.000Z\")", "error": [], diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index 939cd5507ae273..edbe2e839ee25a 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -1945,6 +1945,69 @@ describe('validation logic', () => { }); }); + describe('inline casting', () => { + // accepts casting + testErrorsAndWarnings('from a_index | eval 1::string', []); + + // errors if the cast type is invalid + // testErrorsAndWarnings('from a_index | eval 1::foo', ['Invalid type [foo] for casting']); + + // accepts casting with multiple types + testErrorsAndWarnings('from a_index | eval 1::string::long::double', []); + + // takes into account casting in function arguments + testErrorsAndWarnings('from a_index | eval trim("23"::double)', [ + 'Argument of [trim] must be [string], found value ["23"::double] type [double]', + ]); + testErrorsAndWarnings('from a_index | eval trim(23::string)', []); + testErrorsAndWarnings('from a_index | eval 1 + "2"::long', []); + testErrorsAndWarnings('from a_index | eval 1 + "2"', [ + // just a counter-case to make sure the previous test is meaningful + 'Argument of [+] must be [number], found value ["2"] type [string]', + ]); + testErrorsAndWarnings( + 'from a_index | eval trim(to_double("23")::string::double::long::string::double)', + [ + 'Argument of [trim] must be [string], found value [to_double("23")::string::double::long::string::double] type [double]', + ] + ); + + // accepts elasticsearch subtypes and type aliases like int and keyword + // (once https://github.com/elastic/kibana/issues/174710 is done this won't be a special case anymore) + testErrorsAndWarnings('from a_index | eval CEIL(23::long)', []); + testErrorsAndWarnings('from a_index | eval CEIL(23::unsigned_long)', []); + testErrorsAndWarnings('from a_index | eval CEIL(23::int)', []); + testErrorsAndWarnings('from a_index | eval CEIL(23::integer)', []); + testErrorsAndWarnings('from a_index | eval CEIL(23::double)', []); + + testErrorsAndWarnings('from a_index | eval TRIM(23::string)', []); + testErrorsAndWarnings('from a_index | eval TRIM(23::text)', []); + testErrorsAndWarnings('from a_index | eval TRIM(23::keyword)', []); + + testErrorsAndWarnings('from a_index | eval true AND "false"::boolean', []); + testErrorsAndWarnings('from a_index | eval true AND "false"::bool', []); + testErrorsAndWarnings('from a_index | eval true AND "false"', [ + // just a counter-case to make sure the previous tests are meaningful + 'Argument of [and] must be [boolean], found value ["false"] type [string]', + ]); + + // enforces strings for cartesian_point conversion + // testErrorsAndWarnings('from a_index | eval 23::cartesian_point', ['wrong type!']); + + // still validates nested functions when they are casted + testErrorsAndWarnings('from a_index | eval to_lower(trim(numberField)::string)', [ + 'Argument of [trim] must be [string], found value [numberField] type [number]', + ]); + testErrorsAndWarnings( + 'from a_index | eval to_upper(trim(numberField)::string::string::string::string)', + ['Argument of [trim] must be [string], found value [numberField] type [number]'] + ); + testErrorsAndWarnings( + 'from a_index | eval to_lower(to_upper(trim(numberField)::string)::string)', + ['Argument of [trim] must be [string], found value [numberField] type [number]'] + ); + }); + describe(FUNCTION_DESCRIBE_BLOCK_NAME, () => { describe('date_diff', () => { testErrorsAndWarnings( diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts index 0b44783daef0ec..438d1fd826d00f 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -22,19 +22,18 @@ import type { import { CommandModeDefinition, CommandOptionsDefinition, - FunctionArgSignature, + FunctionParameter, FunctionDefinition, - SignatureArgType, } from '../definitions/types'; import { areFieldAndVariableTypesCompatible, extractSingularType, - getColumnHit, + lookupColumn, getCommandDefinition, getFunctionDefinition, isArrayType, isColumnItem, - isEqualType, + checkFunctionArgMatchesDefinition, isFunctionItem, isLiteralItem, isOptionItem, @@ -44,16 +43,18 @@ import { inKnownTimeInterval, printFunctionSignature, sourceExists, - columnExists, + getColumnExists, hasWildcard, hasCCSSource, isSettingItem, isAssignment, isVariable, isValidLiteralOption, + getQuotedColumnName, + isInlineCastItem, } from '../shared/helpers'; import { collectVariables } from '../shared/variables'; -import { getMessageFromId, getUnknownTypeLabel } from './errors'; +import { getMessageFromId } from './errors'; import type { ErrorTypes, ESQLRealField, @@ -77,7 +78,7 @@ import { METADATA_FIELDS } from '../shared/constants'; function validateFunctionLiteralArg( astFunction: ESQLFunction, actualArg: ESQLAstItem, - argDef: FunctionArgSignature, + argDef: FunctionParameter, references: ReferenceMaps, parentCommand: string ) { @@ -101,7 +102,7 @@ function validateFunctionLiteralArg( ); } - if (!isEqualType(actualArg, argDef, references, parentCommand)) { + if (!checkFunctionArgMatchesDefinition(actualArg, argDef, references, parentCommand)) { messages.push( getMessageFromId({ messageId: 'wrongArgumentType', @@ -129,7 +130,7 @@ function validateFunctionLiteralArg( }) ); } else { - if (!isEqualType(actualArg, argDef, references, parentCommand)) { + if (!checkFunctionArgMatchesDefinition(actualArg, argDef, references, parentCommand)) { messages.push( getMessageFromId({ messageId: 'wrongArgumentType', @@ -148,10 +149,39 @@ function validateFunctionLiteralArg( return messages; } +function validateInlineCastArg( + astFunction: ESQLFunction, + arg: ESQLAstItem, + parameterDefinition: FunctionParameter, + references: ReferenceMaps, + parentCommand: string +) { + if (!isInlineCastItem(arg)) { + return []; + } + + if (!checkFunctionArgMatchesDefinition(arg, parameterDefinition, references, parentCommand)) { + return [ + getMessageFromId({ + messageId: 'wrongArgumentType', + values: { + name: astFunction.name, + argType: parameterDefinition.type, + value: arg.text, + givenType: arg.castType, + }, + locations: arg.location, + }), + ]; + } + + return []; +} + function validateNestedFunctionArg( astFunction: ESQLFunction, actualArg: ESQLAstItem, - argDef: SignatureArgType, + parameterDefinition: FunctionParameter, references: ReferenceMaps, parentCommand: string ) { @@ -165,7 +195,11 @@ function validateNestedFunctionArg( const argFn = getFunctionDefinition(actualArg.name)!; const fnDef = getFunctionDefinition(astFunction.name)!; // no nestying criteria should be enforced only for same type function - if ('noNestingFunctions' in argDef && argDef.noNestingFunctions && fnDef.type === argFn.type) { + if ( + 'noNestingFunctions' in parameterDefinition && + parameterDefinition.noNestingFunctions && + fnDef.type === argFn.type + ) { messages.push( getMessageFromId({ messageId: 'noNestedArgumentSupport', @@ -174,13 +208,15 @@ function validateNestedFunctionArg( }) ); } - if (!isEqualType(actualArg, argDef, references, parentCommand)) { + if ( + !checkFunctionArgMatchesDefinition(actualArg, parameterDefinition, references, parentCommand) + ) { messages.push( getMessageFromId({ messageId: 'wrongArgumentType', values: { name: astFunction.name, - argType: argDef.type, + argType: parameterDefinition.type, value: printFunctionSignature(actualArg) || actualArg.name, givenType: argFn.signatures[0].returnType, }, @@ -195,85 +231,82 @@ function validateNestedFunctionArg( function validateFunctionColumnArg( astFunction: ESQLFunction, actualArg: ESQLAstItem, - argDef: SignatureArgType, + parameterDefinition: FunctionParameter, references: ReferenceMaps, parentCommand: string ) { const messages: ESQLMessage[] = []; - if (isColumnItem(actualArg)) { - if (actualArg.name) { - const { hit: columnCheck, nameHit } = columnExists(actualArg, references); - if (!columnCheck) { - if (argDef.constantOnly) { - messages.push( - getMessageFromId({ - messageId: 'expectedConstant', - values: { - fn: astFunction.name, - given: getUnknownTypeLabel(), - }, - locations: actualArg.location, - }) - ); - } else { - messages.push( - getMessageFromId({ - messageId: 'unknownColumn', - values: { - name: actualArg.name, - }, - locations: actualArg.location, - }) - ); - } - } else { - if (argDef.constantOnly) { - messages.push( - getMessageFromId({ - messageId: 'expectedConstant', - values: { - fn: astFunction.name, - given: actualArg.name, - }, - locations: actualArg.location, - }) - ); - } - if (actualArg.name === '*') { - // if function does not support wildcards return a specific error - if (!('supportsWildcard' in argDef) || !argDef.supportsWildcard) { - messages.push( - getMessageFromId({ - messageId: 'noWildcardSupportAsArg', - values: { - name: astFunction.name, - }, - locations: actualArg.location, - }) - ); - } - // do not validate any further for now, only count() accepts wildcard as args... - } else { - if (!isEqualType(actualArg, argDef, references, parentCommand, nameHit)) { - // guaranteed by the check above - const columnHit = getColumnHit(nameHit!, references); - messages.push( - getMessageFromId({ - messageId: 'wrongArgumentType', - values: { - name: astFunction.name, - argType: argDef.type, - value: actualArg.name, - givenType: columnHit!.type, - }, - locations: actualArg.location, - }) - ); - } - } - } + if (!isColumnItem(actualArg)) { + return messages; + } + + const columnName = getQuotedColumnName(actualArg); + const columnExists = getColumnExists(actualArg, references); + + if (parameterDefinition.constantOnly) { + messages.push( + getMessageFromId({ + messageId: 'expectedConstant', + values: { + fn: astFunction.name, + given: columnName, + }, + locations: actualArg.location, + }) + ); + + return messages; + } + + if (!columnExists) { + messages.push( + getMessageFromId({ + messageId: 'unknownColumn', + values: { + name: actualArg.name, + }, + locations: actualArg.location, + }) + ); + + return messages; + } + + if (actualArg.name === '*') { + // if function does not support wildcards return a specific error + if (!('supportsWildcard' in parameterDefinition) || !parameterDefinition.supportsWildcard) { + messages.push( + getMessageFromId({ + messageId: 'noWildcardSupportAsArg', + values: { + name: astFunction.name, + }, + locations: actualArg.location, + }) + ); } + + return messages; } + + if ( + !checkFunctionArgMatchesDefinition(actualArg, parameterDefinition, references, parentCommand) + ) { + const columnHit = lookupColumn(actualArg, references); + messages.push( + getMessageFromId({ + messageId: 'wrongArgumentType', + values: { + name: astFunction.name, + argType: parameterDefinition.type, + value: actualArg.name, + givenType: columnHit!.type, + }, + locations: actualArg.location, + }) + ); + } + return messages; } @@ -292,6 +325,13 @@ function extractCompatibleSignaturesForFunction( }); } +function removeInlineCasts(arg: ESQLAstItem): ESQLAstItem { + if (isInlineCastItem(arg)) { + return removeInlineCasts(arg.value); + } + return arg; +} + function validateFunction( astFunction: ESQLFunction, parentCommand: string, @@ -396,7 +436,15 @@ function validateFunction( return signature.params[i]?.constantOnly; }); const wrappedArray = Array.isArray(arg) ? arg : [arg]; - for (const subArg of wrappedArray) { + for (const _subArg of wrappedArray) { + /** + * we need to remove the inline casts + * to see if there's a function under there + * + * e.g. for ABS(CEIL(numberField)::int), we need to validate CEIL(numberField) + */ + const subArg = removeInlineCasts(_subArg); + if (isFunctionItem(subArg)) { const messagesFromArg = validateFunction( subArg, @@ -473,6 +521,7 @@ function validateFunction( validateFunctionLiteralArg, validateNestedFunctionArg, validateFunctionColumnArg, + validateInlineCastArg, ].flatMap((validateFn) => { return validateFn( astFunction, @@ -682,14 +731,14 @@ function validateColumnForCommand( ); } } else { - const { hit: columnCheck, nameHit } = columnExists(column, references); - if (columnCheck && nameHit) { + const columnName = getQuotedColumnName(column); + if (getColumnExists(column, references)) { const commandDef = getCommandDefinition(commandName); const columnParamsWithInnerTypes = commandDef.signature.params.filter( ({ type, innerType }) => type === 'column' && innerType ); // this should be guaranteed by the columnCheck above - const columnRef = getColumnHit(nameHit, references)!; + const columnRef = lookupColumn(column, references)!; if (columnParamsWithInnerTypes.length) { const hasSomeWrongInnerTypes = columnParamsWithInnerTypes.every(({ innerType }) => { @@ -706,7 +755,7 @@ function validateColumnForCommand( type: supportedTypes.join(', '), typeCount: supportedTypes.length, givenType: columnRef.type, - column: nameHit, + column: columnName, }, locations: column.location, }) @@ -714,7 +763,7 @@ function validateColumnForCommand( } } if ( - hasWildcard(nameHit) && + hasWildcard(columnName) && !isVariable(columnRef) && !commandDef.signature.params.some(({ type, wildcards }) => type === 'column' && wildcards) ) { @@ -723,7 +772,7 @@ function validateColumnForCommand( messageId: 'wildcardNotSupportedForCommand', values: { command: commandName.toUpperCase(), - value: nameHit, + value: columnName, }, locations: column.location, }) From 92e70949f2b4ecb162c223e7c62a41052bc32ca8 Mon Sep 17 00:00:00 2001 From: Jill Guyonnet Date: Tue, 18 Jun 2024 13:52:39 +0100 Subject: [PATCH 026/123] [Fleet] Mark new Fleet-managed tags SO with `managed: true` (#185972) ## Summary Closes https://github.com/elastic/kibana/issues/176924 This is part 1 of making all Fleet-managed tags with the `managed: true` property in the Saved Object. With this change, new tags are created with `managed: true`. As discussed in https://github.com/elastic/kibana/issues/176924, a followup effort will be required to backfill existing tags. ### Steps to reproduce 1. Boot up a fresh ES instance with no prior data and start Kibana on `main`. 2. Go to Stack Management -> Tags: there should be no pre-existing tags. 3. In Fleet, create an agent policy with the System integration. 4. Go back to Stack Management -> Tags: there should be 4 non-managed tags: Screenshot 2024-06-13 at 16 22 39 5. Check out this branch and restart Kibana. 6. Install another integration, e.g. Apache HTTP Server. 7. Go back to Stack Management -> Tags: a new tag should have been created for the new integration. This tag should be managed and not editable in the UI: Screenshot 2024-06-13 at 16 25 53 8. (Optional): you can also check that this works for a new stack by starting a fresh ES instance and Kibana on this branch. In step 4 above, the 4 tags created after creating the agent policy with System should all be managed and not editable: Screenshot 2024-06-13 at 16 29 22 NB: the 4 tags created in the flow above reflect 3 different types of tag: - the `Managed` tag which all package assets are tagged with - package tags (`Elastic Agent` and `System` in this case) - tags defined in the integration's `tag.yml` ([in system's case](https://github.com/elastic/integrations/blob/main/packages/system/kibana/tags.yml), that's `Security Solution`) ### Checklist - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../saved_objects_tagging_oss/common/types.ts | 1 + .../epm/kibana/assets/tag_assets.test.ts | 48 +++++++++++++------ .../services/epm/kibana/assets/tag_assets.ts | 6 +-- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/plugins/saved_objects_tagging_oss/common/types.ts b/src/plugins/saved_objects_tagging_oss/common/types.ts index 58384465027c66..f72aabfb7fd02a 100644 --- a/src/plugins/saved_objects_tagging_oss/common/types.ts +++ b/src/plugins/saved_objects_tagging_oss/common/types.ts @@ -30,6 +30,7 @@ export interface CreateTagOptions { id?: string; overwrite?: boolean; refresh?: boolean | 'wait_for'; + managed?: boolean; } export interface ITagsClient { diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts index f3d59c9607a386..82989715be0e14 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts @@ -24,7 +24,12 @@ describe('tagKibanaAssets', () => { description: '', name: 'Managed', }; - const managedTagPayloadArg2 = { id: 'fleet-managed-default', overwrite: true, refresh: false }; + const managedTagPayloadArg2 = { + id: 'fleet-managed-default', + overwrite: true, + refresh: false, + managed: true, + }; beforeEach(() => { savedObjectTagAssignmentService.updateTagAssignments.mockReset(); @@ -55,7 +60,7 @@ describe('tagKibanaAssets', () => { description: '', color: '#0077CC', }, - { id: 'fleet-managed-default', overwrite: true, refresh: false } + { id: 'fleet-managed-default', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagClient.create).toHaveBeenCalledWith( { @@ -63,7 +68,7 @@ describe('tagKibanaAssets', () => { description: '', color: '#4DD2CA', }, - { id: 'fleet-pkg-system-default', overwrite: true, refresh: false } + { id: 'fleet-pkg-system-default', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ tags: ['fleet-managed-default', 'fleet-pkg-system-default'], @@ -201,7 +206,7 @@ describe('tagKibanaAssets', () => { description: '', color: '#0077CC', }, - { id: 'fleet-managed-default', overwrite: true, refresh: false } + { id: 'fleet-managed-default', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagClient.create).toHaveBeenCalledWith( @@ -210,7 +215,7 @@ describe('tagKibanaAssets', () => { description: '', color: '#4DD2CA', }, - { id: 'fleet-pkg-system-default', overwrite: true, refresh: false } + { id: 'fleet-pkg-system-default', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ tags: ['managed', 'fleet-pkg-system-default'], @@ -248,7 +253,7 @@ describe('tagKibanaAssets', () => { description: '', color: '#0077CC', }, - { id: 'fleet-managed-default', overwrite: true, refresh: false } + { id: 'fleet-managed-default', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagClient.create).not.toHaveBeenCalledWith( @@ -257,7 +262,7 @@ describe('tagKibanaAssets', () => { description: '', color: '#4DD2CA', }, - { id: 'system', overwrite: true, refresh: false } + { id: 'system', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledWith({ tags: ['fleet-managed-default', 'system'], @@ -339,7 +344,7 @@ describe('tagKibanaAssets', () => { description: '', name: 'TestPackage', }, - { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false } + { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagClient.create).toHaveBeenCalledWith( { @@ -351,6 +356,7 @@ describe('tagKibanaAssets', () => { id: FOO_TAG_ID, overwrite: true, refresh: false, + managed: true, } ); expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledTimes(3); @@ -436,7 +442,7 @@ describe('tagKibanaAssets', () => { description: '', name: 'TestPackage', }, - { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false } + { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagClient.create).toHaveBeenCalledWith( { @@ -448,6 +454,7 @@ describe('tagKibanaAssets', () => { id: BAR_TAG_ID, overwrite: true, refresh: false, + managed: true, } ); expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledTimes(3); @@ -538,7 +545,7 @@ describe('tagKibanaAssets', () => { description: '', name: 'TestPackage', }, - { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false } + { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagClient.create).toHaveBeenCalledWith( { @@ -550,6 +557,7 @@ describe('tagKibanaAssets', () => { id: MY_CUSTOM_TAG_ID, overwrite: true, refresh: false, + managed: true, } ); expect(savedObjectTagAssignmentService.updateTagAssignments).toHaveBeenCalledTimes(3); @@ -684,7 +692,7 @@ describe('tagKibanaAssets', () => { description: '', color: '#4DD2CA', }, - { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false } + { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false, managed: true } ); }); @@ -728,7 +736,7 @@ describe('tagKibanaAssets', () => { description: '', name: 'TestPackage', }, - { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false } + { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false, managed: true } ); expect(savedObjectTagClient.create).toHaveBeenCalledWith( { @@ -736,7 +744,7 @@ describe('tagKibanaAssets', () => { description: 'Tag defined in package-spec', name: 'Security Solution', }, - { id: 'security-solution-default', overwrite: true, refresh: false } + { id: 'security-solution-default', overwrite: true, refresh: false, managed: true } ); }); @@ -779,7 +787,12 @@ describe('tagKibanaAssets', () => { description: '', name: 'TestPackage', }, - { id: 'fleet-pkg-test-pkg-my-secondary-space', overwrite: true, refresh: false } + { + id: 'fleet-pkg-test-pkg-my-secondary-space', + overwrite: true, + refresh: false, + managed: true, + } ); expect(savedObjectTagClient.create).toHaveBeenCalledWith( { @@ -787,7 +800,12 @@ describe('tagKibanaAssets', () => { description: 'Tag defined in package-spec', name: 'Security Solution', }, - { id: 'security-solution-my-secondary-space', overwrite: true, refresh: false } + { + id: 'security-solution-my-secondary-space', + overwrite: true, + refresh: false, + managed: true, + } ); }); }); diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts index 5e7d4477bbbd3c..86127c19e28116 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts @@ -179,7 +179,7 @@ async function ensureManagedTag( description: '', color: MANAGED_TAG_COLOR, }, - { id: managedTagId, overwrite: true, refresh: false } + { id: managedTagId, overwrite: true, refresh: false, managed: true } ); return managedTagId; @@ -206,7 +206,7 @@ async function ensurePackageTag( description: '', color: PACKAGE_TAG_COLOR, }, - { id: packageTagId, overwrite: true, refresh: false } + { id: packageTagId, overwrite: true, refresh: false, managed: true } ); return packageTagId; @@ -232,7 +232,7 @@ async function getPackageSpecTags( description: 'Tag defined in package-spec', color: getRandomColor(), }, - { id: uniqueTagId, overwrite: true, refresh: false } + { id: uniqueTagId, overwrite: true, refresh: false, managed: true } ); } const assetTypes = getAssetTypesObjectReferences(tag?.asset_types, taggableAssets); From 27d967afcaf45645182f3ea129f2a145414d9f0d Mon Sep 17 00:00:00 2001 From: Jill Guyonnet Date: Tue, 18 Jun 2024 13:53:05 +0100 Subject: [PATCH 027/123] [Fleet] Fix serverless message in edit output flyout (#186183) ## Summary This PR fixes a bug where the message `Custom host URLs are not allowed in serverless.` is shown above the URL input in the flyout for editing the default Fleet Server host and default output. ### Screenshots #### Stateful Screenshot 2024-06-13 at 15 20 45 Screenshot 2024-06-13 at 15 20 54 #### Serverless Screenshot 2024-06-13 at 15 24 54 Screenshot 2024-06-13 at 15 25 02 Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../edit_output_flyout/output_form_elasticsearch.tsx | 5 ++++- .../settings/components/fleet_server_hosts_flyout/index.tsx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_elasticsearch.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_elasticsearch.tsx index 21e43fcba001ae..bf79932416f5a9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_elasticsearch.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_elasticsearch.tsx @@ -12,6 +12,8 @@ import { i18n } from '@kbn/i18n'; import { MultiRowInput } from '../multi_row_input'; +import { useStartServices } from '../../../../hooks'; + import type { OutputFormInputsType } from './use_output_form'; interface Props { @@ -20,6 +22,7 @@ interface Props { export const OutputFormElasticsearchSection: React.FunctionComponent = (props) => { const { inputs } = props; + const { cloud } = useStartServices(); return ( <> @@ -37,7 +40,7 @@ export const OutputFormElasticsearchSection: React.FunctionComponent = (p {...inputs.elasticsearchUrlInput.props} isUrl helpText={ - inputs.elasticsearchUrlInput.props.disabled && ( + cloud?.isServerlessEnabled && ( Date: Tue, 18 Jun 2024 13:53:56 +0100 Subject: [PATCH 028/123] [Fleet] Fix KQL filtering (#183757) ## Summary Closes https://github.com/elastic/kibana/issues/178069 This PR fixes agent policies KQL filtering in Fleet UI. Because agent policy data is retrieved from Saved Objects, the policy fields require the SO prefix (`ingest-agent-policies`), which was removed in https://github.com/elastic/kibana/pull/161064, to be present (see https://github.com/elastic/kibana/issues/178069#issuecomment-2154800178 for details). [A further ER](https://github.com/elastic/kibana/issues/185921) captures the requirements for displaying custom labels without the prefix. In Fleet UI, the `SearchBar` component that uses KQL filtering is used in three tabs: - Agents - Agent policies - Enrollment tokens Note that the search inputs in the Uninstall tokens and Data streams tabs are simple text filtering, not KQL. The filtering behaviour with this fix matches the one in 8.11.0 and is captured in the screen recording below: - Agents tab: agent fields (e.g. `policy_id` or `agent.version`) - Agent policies tab: agent policy fields prefixed with `ingest-agent-policies` (e.g. `ingest-agent-policies.name`) - Enrollment tokens tab: token fields (e.g. `name` or `policy_id`) ### Screen recording This screen recording shows working KQL filtering and suggestions for the three tabs (fixed for Agent policies): https://github.com/elastic/kibana/assets/23701614/db4a7de7-a098-497a-a3c8-075ed5d0425e ### Testing 1. Create a few agent policies and enroll a couple of agents. 2. Test that the expected fields are shown in the KQL search bars for agents, agent policies and enrollment tokens. For each, check that suggestions are shown when you select a particular field with existing values. 3. For agent policies in particular, also check that KQL syntax works as expect. For instance, if you have an agent policy named "Test agent policy", the query `ingest-agent-policies.name : *agent*` should correctly filter for it. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../fleet/components/search_bar.test.tsx | 71 +++++++++---------- .../fleet/components/search_bar.tsx | 60 +++++++++------- .../sections/agent_policy/list_page/index.tsx | 6 +- .../components/search_and_filter_bar.tsx | 4 +- .../enrollment_token_list_page/index.tsx | 4 +- .../plugins/fleet/public/constants/index.ts | 4 ++ 6 files changed, 81 insertions(+), 68 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.test.tsx index c33a0427b5000e..d572a00ec22418 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.test.tsx @@ -15,8 +15,11 @@ import { createFleetTestRendererMock } from '../../../mock'; import { AGENTS_PREFIX, FLEET_ENROLLMENT_API_PREFIX, - PACKAGE_POLICY_SAVED_OBJECT_TYPE, AGENT_POLICY_SAVED_OBJECT_TYPE, + AGENTS_INDEX, + ENROLLMENT_API_KEYS_INDEX, + INGEST_SAVED_OBJECT_INDEX, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, } from '../constants'; import { SearchBar, getFieldSpecs } from './search_bar'; @@ -169,13 +172,12 @@ describe('SearchBar', () => { }); describe('getFieldSpecs', () => { - it('returns fieldSpecs for fleet-agents', () => { - expect(getFieldSpecs(`.${AGENTS_PREFIX}`)).toHaveLength(67); + it('returns fieldSpecs for Fleet agents', () => { + expect(getFieldSpecs(AGENTS_INDEX, AGENTS_PREFIX)).toHaveLength(67); }); - it('returns getFieldSpecs for fleet-enrollment-api-keys', () => { - const indexPattern = `.${FLEET_ENROLLMENT_API_PREFIX}`; - expect(getFieldSpecs(indexPattern)).toHaveLength(8); - expect(getFieldSpecs(indexPattern)).toEqual([ + + it('returns fieldSpecs for Fleet enrollment tokens', () => { + expect(getFieldSpecs(ENROLLMENT_API_KEYS_INDEX, FLEET_ENROLLMENT_API_PREFIX)).toEqual([ { aggregatable: true, esTypes: ['boolean'], @@ -235,176 +237,173 @@ describe('getFieldSpecs', () => { ]); }); - it('returns getFieldSpecs for fleet-agent-policy', () => { - const indexPattern = `.${AGENT_POLICY_SAVED_OBJECT_TYPE}`; - expect(getFieldSpecs(indexPattern)).toHaveLength(23); - expect(getFieldSpecs(indexPattern)).toEqual([ + it('returns fieldSpecs for Fleet agent policies', () => { + expect(getFieldSpecs(INGEST_SAVED_OBJECT_INDEX, AGENT_POLICY_SAVED_OBJECT_TYPE)).toEqual([ { aggregatable: true, esTypes: ['keyword'], - name: 'agent_features.name', + name: 'ingest-agent-policies.agent_features.name', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['boolean'], - name: 'agent_features.enabled', + name: 'ingest-agent-policies.agent_features.enabled', searchable: true, type: 'boolean', }, { aggregatable: true, esTypes: ['keyword'], - name: 'data_output_id', + name: 'ingest-agent-policies.data_output_id', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['text'], - name: 'description', + name: 'ingest-agent-policies.description', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['keyword'], - name: 'download_source_id', + name: 'ingest-agent-policies.download_source_id', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['keyword'], - name: 'fleet_server_host_id', + name: 'ingest-agent-policies.fleet_server_host_id', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['integer'], - name: 'inactivity_timeout', + name: 'ingest-agent-policies.inactivity_timeout', searchable: true, type: 'number', }, { aggregatable: true, esTypes: ['boolean'], - name: 'is_default', + name: 'ingest-agent-policies.is_default', searchable: true, type: 'boolean', }, { aggregatable: true, esTypes: ['boolean'], - name: 'is_default_fleet_server', + name: 'ingest-agent-policies.is_default_fleet_server', searchable: true, type: 'boolean', }, { aggregatable: true, esTypes: ['boolean'], - name: 'is_managed', + name: 'ingest-agent-policies.is_managed', searchable: true, type: 'boolean', }, { aggregatable: true, esTypes: ['keyword'], - name: 'is_preconfigured', + name: 'ingest-agent-policies.is_preconfigured', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['boolean'], - name: 'is_protected', + name: 'ingest-agent-policies.is_protected', searchable: true, type: 'boolean', }, { aggregatable: true, esTypes: ['keyword'], - name: 'monitoring_enabled', + name: 'ingest-agent-policies.monitoring_enabled', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['false'], - name: 'monitoring_enabled.index', + name: 'ingest-agent-policies.monitoring_enabled.index', searchable: true, type: 'false', }, { aggregatable: true, esTypes: ['keyword'], - name: 'monitoring_output_id', + name: 'ingest-agent-policies.monitoring_output_id', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['keyword'], - name: 'name', + name: 'ingest-agent-policies.name', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['keyword'], - name: 'namespace', + name: 'ingest-agent-policies.namespace', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['integer'], - name: 'revision', + name: 'ingest-agent-policies.revision', searchable: true, type: 'number', }, { aggregatable: true, esTypes: ['version'], - name: 'schema_version', + name: 'ingest-agent-policies.schema_version', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['keyword'], - name: 'status', + name: 'ingest-agent-policies.status', searchable: true, type: 'string', }, { aggregatable: true, esTypes: ['integer'], - name: 'unenroll_timeout', + name: 'ingest-agent-policies.unenroll_timeout', searchable: true, type: 'number', }, { aggregatable: true, esTypes: ['date'], - name: 'updated_at', + name: 'ingest-agent-policies.updated_at', searchable: true, type: 'date', }, { aggregatable: true, esTypes: ['keyword'], - name: 'updated_by', + name: 'ingest-agent-policies.updated_by', searchable: true, type: 'string', }, ]); }); - expect(getFieldSpecs(`.${PACKAGE_POLICY_SAVED_OBJECT_TYPE}`)).toHaveLength(19); it('returns empty array if indexPattern is not one of the previous', async () => { - expect(getFieldSpecs('.kibana_ingest')).toEqual([]); + expect(getFieldSpecs(INGEST_SAVED_OBJECT_INDEX, PACKAGE_POLICY_SAVED_OBJECT_TYPE)).toEqual([]); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx index 6f23d25f381254..3e47a3a7955b32 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx @@ -16,19 +16,15 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import { i18n } from '@kbn/i18n'; import { useStartServices } from '../hooks'; -import { - INDEX_NAME, - AGENTS_PREFIX, - FLEET_ENROLLMENT_API_PREFIX, - PACKAGE_POLICY_SAVED_OBJECT_TYPE, - AGENT_POLICY_SAVED_OBJECT_TYPE, -} from '../constants'; import { AGENT_POLICY_MAPPINGS, - PACKAGE_POLICIES_MAPPINGS, AGENT_MAPPINGS, ENROLLMENT_API_KEY_MAPPINGS, -} from '../../../../common/constants'; + AGENTS_INDEX, + ENROLLMENT_API_KEYS_INDEX, + AGENT_POLICY_SAVED_OBJECT_TYPE, + INGEST_SAVED_OBJECT_INDEX, +} from '../constants'; const NoWrapQueryStringInput = styled(QueryStringInput)` .kbnQueryBar__textarea { @@ -38,29 +34,42 @@ const NoWrapQueryStringInput = styled(QueryStringInput)` interface Props { value: string; - fieldPrefix?: string; + indexPattern: string; + fieldPrefix: string; onChange: (newValue: string, submit?: boolean) => void; placeholder?: string; - indexPattern?: string; dataTestSubj?: string; } -const getMappings = (indexPattern: string) => { +const getMappings = (indexPattern: string, fieldPrefix: string) => { switch (indexPattern) { - case `.${AGENTS_PREFIX}`: + case AGENTS_INDEX: return AGENT_MAPPINGS; - case `.${AGENT_POLICY_SAVED_OBJECT_TYPE}`: - return AGENT_POLICY_MAPPINGS; - case `.${PACKAGE_POLICY_SAVED_OBJECT_TYPE}`: - return PACKAGE_POLICIES_MAPPINGS; - case `.${FLEET_ENROLLMENT_API_PREFIX}`: + // Saved Objects are stored in .kibana_ingest. + // Currently, the search bar is only used to query agent policies. + case INGEST_SAVED_OBJECT_INDEX: + switch (fieldPrefix) { + case AGENT_POLICY_SAVED_OBJECT_TYPE: + return AGENT_POLICY_MAPPINGS; + default: + return {}; + } + case ENROLLMENT_API_KEYS_INDEX: return ENROLLMENT_API_KEY_MAPPINGS; default: return {}; } }; -const getType = (type: string) => { +const getFieldName = (indexPattern: string, fieldPrefix: string, name: string) => { + // Add Saved Object prefix if the field refers to a SO and is not already prefixed. + if (indexPattern !== INGEST_SAVED_OBJECT_INDEX || name.startsWith(fieldPrefix)) { + return name; + } + return `${fieldPrefix}.${name}`; +}; + +const getFieldType = (type: string) => { switch (type) { case 'keyword': return 'string'; @@ -88,9 +97,10 @@ const concatKeys = (obj: any, parentKey = '') => { } return result; }; + /** Exported for testing only **/ -export const getFieldSpecs = (indexPattern: string) => { - const mapping = getMappings(indexPattern); +export const getFieldSpecs = (indexPattern: string, fieldPrefix: string) => { + const mapping = getMappings(indexPattern, fieldPrefix); // @ts-ignore-next-line const rawFields = concatKeys(mapping?.properties) || []; const fields = rawFields @@ -100,8 +110,8 @@ export const getFieldSpecs = (indexPattern: string) => { const fieldSpecs: FieldSpec[] = fields.map((field) => { return { - name: field[0], - type: getType(field[1]), + name: getFieldName(indexPattern, fieldPrefix, field[0]), + type: getFieldType(field[1]), searchable: true, aggregatable: true, esTypes: [field[1]], @@ -115,7 +125,7 @@ export const SearchBar: React.FunctionComponent = ({ fieldPrefix, onChange, placeholder, - indexPattern = INDEX_NAME, + indexPattern, dataTestSubj, }) => { const { @@ -148,7 +158,7 @@ export const SearchBar: React.FunctionComponent = ({ useEffect(() => { const fetchFields = async () => { try { - const fieldSpecs = getFieldSpecs(indexPattern); + const fieldSpecs = getFieldSpecs(indexPattern, fieldPrefix); const fieldsMap = data.dataViews.fieldArrayToMap(fieldSpecs); const newDataView = await data.dataViews.create( { title: indexPattern, fields: fieldsMap }, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx index a2e0e6663e5cf8..40f057b56551cf 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx @@ -25,7 +25,7 @@ import { useHistory } from 'react-router-dom'; import type { AgentPolicy } from '../../../types'; import { getRootIntegrations } from '../../../../../../common/services'; -import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../constants'; +import { AGENT_POLICY_SAVED_OBJECT_TYPE, INGEST_SAVED_OBJECT_INDEX } from '../../../constants'; import { useAuthz, usePagination, @@ -320,6 +320,8 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { { setPagination({ ...pagination, @@ -327,8 +329,6 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { }); setSearch(newSearch); }} - indexPattern={`.${AGENT_POLICY_SAVED_OBJECT_TYPE}`} - fieldPrefix={AGENT_POLICY_SAVED_OBJECT_TYPE} dataTestSubj="agentPolicyList.queryInput" /> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/search_and_filter_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/search_and_filter_bar.tsx index b0f6223193170d..718684606f9d73 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/search_and_filter_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/search_and_filter_bar.tsx @@ -163,14 +163,14 @@ export const SearchAndFilterBar: React.FunctionComponent { onDraftKueryChange(newSearch); if (submit) { onSubmitSearch(newSearch); } }} - fieldPrefix={AGENTS_PREFIX} - indexPattern={AGENTS_INDEX} dataTestSubj="agentList.queryInput" /> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx index b72794868a1c2f..3a21103503ae5a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx @@ -245,6 +245,8 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { { setPagination({ ...pagination, @@ -252,8 +254,6 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { }); setSearch(newSearch); }} - indexPattern={ENROLLMENT_API_KEYS_INDEX} - fieldPrefix={FLEET_ENROLLMENT_API_PREFIX} dataTestSubj="enrollmentKeysList.queryInput" /> diff --git a/x-pack/plugins/fleet/public/constants/index.ts b/x-pack/plugins/fleet/public/constants/index.ts index ee01037f25a788..1c0a04b9cb8a71 100644 --- a/x-pack/plugins/fleet/public/constants/index.ts +++ b/x-pack/plugins/fleet/public/constants/index.ts @@ -28,6 +28,10 @@ export { AUTO_UPGRADE_POLICIES_PACKAGES, LOCATORS_IDS, FLEET_ENROLLMENT_API_PREFIX, + INGEST_SAVED_OBJECT_INDEX, + AGENT_POLICY_MAPPINGS, + AGENT_MAPPINGS, + ENROLLMENT_API_KEY_MAPPINGS, } from '../../common/constants'; export * from './page_paths'; From b98fc1418bfd607fa5ff983055f762a8cd50fb8b Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 18 Jun 2024 08:13:09 -0500 Subject: [PATCH 029/123] [ci] Prevent alerts for spot preemptions (#186329) After migrating to gobld, the string identifying spot instances has changed. This updates the check to determine if there are retries available by filtering on the metadata for both gobld and buildkite-agent-manager. --- .buildkite/pipeline-utils/buildkite/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/pipeline-utils/buildkite/client.ts b/.buildkite/pipeline-utils/buildkite/client.ts index be2cb81dd51c0f..c58c3cb7e42e3f 100644 --- a/.buildkite/pipeline-utils/buildkite/client.ts +++ b/.buildkite/pipeline-utils/buildkite/client.ts @@ -282,7 +282,7 @@ export class BuildkiteClient { hasRetries = true; const isPreemptionFailure = job.state === 'failed' && - job.agent?.meta_data?.includes('spot=true') && + job.agent?.meta_data?.some((el) => ['spot=true', 'gcp:preemptible=true'].includes(el)) && job.exit_status === -1; if (!isPreemptionFailure) { From c8bd58c9759626b96e6276595363f62800dc4d4d Mon Sep 17 00:00:00 2001 From: Miriam <31922082+MiriamAparicio@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:18:43 +0100 Subject: [PATCH 030/123] [ObsUX][Infra] Fix container metrics not showing correct fields for docker (#186363) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Some conditions were not correct on the render of the KPI, this didn’t show in the e2e tests because with synthtrace we just generate data for docker without kubernetes fields so it will be always showing docker fields. Apparently is possible to have both docker and k8s fields (kubernetes.container & docker.container), at least on the test data we have on the oblt-clusters. What we did is check if docker.container or kubernetes.container exist, in case of none, charts will not display, in case of both we show docker metric charts, otherwise k8s metrics charts For the metrics section the condition was correct but not for the KPIs --- .../components/kpis/container_kpi_charts.tsx | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/components/kpis/container_kpi_charts.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/components/kpis/container_kpi_charts.tsx index 26ecccc7f15410..c2f61b97257fcb 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/components/kpis/container_kpi_charts.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/components/kpis/container_kpi_charts.tsx @@ -44,24 +44,30 @@ export const ContainerKpiCharts = ({ if (!isDockerContainer && !isKubernetesContainer) { return null; } - return isKubernetesContainer ? ( - - ) : ( - + + return ( + <> + {isDockerContainer && ( + + )} + {!isDockerContainer && isKubernetesContainer && ( + + )} + ); }; From c34bb46c8aeb59dca0c92132dd34d2d9fca68728 Mon Sep 17 00:00:00 2001 From: Mark Hopkin Date: Tue, 18 Jun 2024 14:27:26 +0100 Subject: [PATCH 031/123] [Entity Analytics] Flaky Cypress test fixes (#186081) ### Fix 1: Press refresh button after using date picker on dashboard Closes https://github.com/elastic/kibana/issues/183662 Closes https://github.com/elastic/kibana/issues/183635 Closes https://github.com/elastic/kibana/issues/183982 We shouldnt have to do this, but there is some condition where clicking apply gets the UI in a stuck state and I cant figure it out. ### Fix 2: Use more specific selector for search bar on risk score preview page Closes https://github.com/elastic/kibana/issues/184133 We were using a generic selector `[data-test-subj="unifiedQueryInput"] textarea` which was bringing back two elements sometimes (no idea why), I have given the box its own dedicated selector to hopefully prevent this from happening --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/risk_score_preview_section.tsx | 1 + .../dashboards/entity_analytics/new_risk_score.cy.ts | 2 ++ .../entity_analytics_management_page.cy.ts | 9 ++++----- .../cypress/screens/entity_analytics_management.ts | 3 +++ .../cypress/tasks/entity_analytics.ts | 6 +++--- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_preview_section.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_preview_section.tsx index 91383fcdfd6581..b8f7870e23b562 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_preview_section.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_score_preview_section.tsx @@ -227,6 +227,7 @@ const RiskEnginePreview = () => { showDatePicker={true} displayStyle={'inPage'} submitButtonStyle={'iconOnly'} + dataTestSubj="risk-score-preview-search-bar-input" /> )} diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/entity_analytics/new_risk_score.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/entity_analytics/new_risk_score.cy.ts index 894248f9ff7165..da59afaec941cb 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/entity_analytics/new_risk_score.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/entity_analytics/new_risk_score.cy.ts @@ -103,6 +103,7 @@ describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () => describe('With host risk data', () => { before(() => { + cy.task('esArchiverUnload', { archiveName: 'risk_scores_new' }); cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); }); @@ -145,6 +146,7 @@ describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () => describe('With alerts data', () => { before(() => { + deleteAlertsAndRules(); createRule(getNewRule()); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts index fae26fec77fa20..b8d222471c87e5 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/entity_analytics_management_page.cy.ts @@ -15,6 +15,7 @@ import { LOCAL_QUERY_BAR_SELECTOR, RISK_SCORE_ERROR_PANEL, RISK_SCORE_STATUS, + LOCAL_QUERY_BAR_SEARCH_INPUT_SELECTOR, } from '../../screens/entity_analytics_management'; import { deleteRiskScore, installRiskScoreModule } from '../../tasks/api_calls/risk_scores'; @@ -31,7 +32,7 @@ import { interceptRiskInitError, } from '../../tasks/api_calls/risk_engine'; import { updateDateRangeInLocalDatePickers } from '../../tasks/date_picker'; -import { fillLocalSearchBar, submitLocalSearch } from '../../tasks/search_bar'; +import { submitLocalSearch } from '../../tasks/search_bar'; import { riskEngineStatusChange, upgradeRiskEngine, @@ -63,8 +64,7 @@ describe( cy.get(PAGE_TITLE).should('have.text', 'Entity Risk Score'); }); - // FLAKY: https://github.com/elastic/kibana/issues/184133 - describe.skip('Risk preview', () => { + describe('Risk preview', () => { it('risk scores reacts on change in datepicker', () => { const START_DATE = 'Jan 18, 2019 @ 20:33:29.186'; const END_DATE = 'Jan 19, 2019 @ 20:33:29.186'; @@ -81,8 +81,7 @@ describe( it('risk scores reacts on change in search bar query', () => { cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); cy.get(USER_RISK_PREVIEW_TABLE_ROWS).should('have.length', 5); - - fillLocalSearchBar('host.name: "test-host1"'); + cy.get(LOCAL_QUERY_BAR_SEARCH_INPUT_SELECTOR).type('host.name: "test-host1"'); submitLocalSearch(LOCAL_QUERY_BAR_SELECTOR); cy.get(HOST_RISK_PREVIEW_TABLE_ROWS).should('have.length', 1); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts index 481c12fd9232e7..e1d62ffb420c8b 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics_management.ts @@ -23,6 +23,9 @@ export const RISK_PREVIEW_ERROR_BUTTON = '[data-test-subj="risk-preview-error-bu export const LOCAL_QUERY_BAR_SELECTOR = getDataTestSubjectSelector('risk-score-preview-search-bar'); +export const LOCAL_QUERY_BAR_SEARCH_INPUT_SELECTOR = + '[data-test-subj="risk-score-preview-search-bar-input"]'; + export const RISK_SCORE_ERROR_PANEL = '[data-test-subj="risk-score-error-panel"]'; export const RISK_SCORE_UPDATE_CANCEL = '[data-test-subj="risk-score-update-cancel"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts index bb02c196ac92e8..5d84c28100fee9 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts @@ -26,13 +26,13 @@ import { } from '../screens/entity_analytics_management'; import { visitWithTimeRange } from './navigation'; import { GET_DATE_PICKER_APPLY_BUTTON, GLOBAL_FILTERS_CONTAINER } from '../screens/date_picker'; -import { LOADING_SPINNER } from '../screens/loading'; +import { REFRESH_BUTTON } from '../screens/security_header'; export const updateDashboardTimeRange = () => { // eslint-disable-next-line cypress/no-force cy.get(GET_DATE_PICKER_APPLY_BUTTON(GLOBAL_FILTERS_CONTAINER)).click({ force: true }); // Force to fix global timerange flakiness - cy.get(LOADING_SPINNER).should('exist'); - cy.get(LOADING_SPINNER).should('not.exist'); + cy.get(REFRESH_BUTTON).click(); + cy.get(REFRESH_BUTTON).should('not.have.attr', 'aria-label', 'Needs updating'); }; export const waitForAnomaliesToBeLoaded = () => { From 51bc0dc039f1fc102f12e959e3f19715cc184a91 Mon Sep 17 00:00:00 2001 From: Ersin Erdal <92688503+ersin-erdal@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:31:16 +0200 Subject: [PATCH 032/123] Add connector and actionTaskParams modelVersions (#184542) Resolves: #177059 This PR adds model versions for `action` and `action_task_params` saved objects. I also re-organised the schema and model version file structure in alerting, task_manager and actions plugins. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../check_registered_types.test.ts | 4 +- .../actions/server/saved_objects/index.ts | 4 + .../action_task_params_model_versions.ts | 18 +++++ .../connector_model_versions.ts | 18 +++++ .../saved_objects/model_versions/index.ts | 9 +++ .../schemas/action_task_params/index.ts | 8 ++ .../schemas/action_task_params/v1.ts | 29 +++++++ .../schemas/raw_connector/index.ts | 8 ++ .../schemas/raw_connector/v1.test.ts} | 8 +- .../schemas/raw_connector/v1.ts} | 6 +- .../create_get_alert_indices_alias.test.ts | 1 - x-pack/plugins/alerting/server/plugin.ts | 2 - .../server/rule_type_registry.mock.ts | 1 - .../server/rule_type_registry.test.ts | 11 --- .../alerting/server/rule_type_registry.ts | 8 -- .../ad_hoc_run_params_model_versions.ts | 51 ------------ .../alerting/server/saved_objects/index.ts | 4 +- .../saved_objects/is_rule_exportable.test.ts | 1 - .../ad_hoc_run_params_model_versions.ts | 19 +++++ .../saved_objects/model_versions/index.ts | 9 +++ .../model_versions/rule_model_versions.ts | 18 +++++ .../saved_objects/rule_model_versions.test.ts | 77 ------------------- .../saved_objects/rule_model_versions.ts | 49 ------------ .../server/saved_objects/index.ts | 2 +- .../saved_objects/model_versions/index.ts | 8 ++ .../task_model_versions.ts | 2 +- 26 files changed, 161 insertions(+), 214 deletions(-) create mode 100644 x-pack/plugins/actions/server/saved_objects/model_versions/action_task_params_model_versions.ts create mode 100644 x-pack/plugins/actions/server/saved_objects/model_versions/connector_model_versions.ts create mode 100644 x-pack/plugins/actions/server/saved_objects/model_versions/index.ts create mode 100644 x-pack/plugins/actions/server/saved_objects/schemas/action_task_params/index.ts create mode 100644 x-pack/plugins/actions/server/saved_objects/schemas/action_task_params/v1.ts create mode 100644 x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/index.ts rename x-pack/plugins/actions/server/{raw_connector_schema.test.ts => saved_objects/schemas/raw_connector/v1.test.ts} (93%) rename x-pack/plugins/actions/server/{raw_connector_schema.ts => saved_objects/schemas/raw_connector/v1.ts} (73%) delete mode 100644 x-pack/plugins/alerting/server/saved_objects/ad_hoc_run_params_model_versions.ts create mode 100644 x-pack/plugins/alerting/server/saved_objects/model_versions/ad_hoc_run_params_model_versions.ts create mode 100644 x-pack/plugins/alerting/server/saved_objects/model_versions/index.ts create mode 100644 x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts delete mode 100644 x-pack/plugins/alerting/server/saved_objects/rule_model_versions.test.ts delete mode 100644 x-pack/plugins/alerting/server/saved_objects/rule_model_versions.ts create mode 100644 x-pack/plugins/task_manager/server/saved_objects/model_versions/index.ts rename x-pack/plugins/task_manager/server/saved_objects/{ => model_versions}/task_model_versions.ts (92%) diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index c89ca689dbfc81..2337bbfaaa89e8 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -55,8 +55,8 @@ describe('checking migration metadata changes on all registered SO types', () => expect(hashMap).toMatchInlineSnapshot(` Object { - "action": "cc93fe2c0c76e57c2568c63170e05daea897c136", - "action_task_params": "96e27e7f4e8273ffcd87060221e2b75e81912dd5", + "action": "0e6fc0b74c7312a8c11ff6b14437b93a997358b8", + "action_task_params": "b50cb5c8a493881474918e8d4985e61374ca4c30", "ad_hoc_run_params": "d4e3c5c794151d0a4f5c71e886b2aa638da73ad2", "alert": "3a67d3f1db80af36bd57aaea47ecfef87e43c58f", "api_key_pending_invalidation": "1399e87ca37b3d3a65d269c924eda70726cfe886", diff --git a/x-pack/plugins/actions/server/saved_objects/index.ts b/x-pack/plugins/actions/server/saved_objects/index.ts index e39c3a4a8a383a..a4d7886091fe51 100644 --- a/x-pack/plugins/actions/server/saved_objects/index.ts +++ b/x-pack/plugins/actions/server/saved_objects/index.ts @@ -13,6 +13,7 @@ import type { import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; import { getOldestIdleActionTask } from '@kbn/task-manager-plugin/server'; import { ALERTING_CASES_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; +import { actionTaskParamsModelVersions } from './model_versions'; import { actionMappings, actionTaskParamsMappings, connectorTokenMappings } from './mappings'; import { getActionsMigrations } from './actions_migrations'; import { getActionTaskParamsMigrations } from './action_task_params_migrations'; @@ -25,6 +26,7 @@ import { ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, CONNECTOR_TOKEN_SAVED_OBJECT_TYPE, } from '../constants/saved_objects'; +import { connectorModelVersions } from './model_versions'; export function setupSavedObjects( savedObjects: SavedObjectsServiceSetup, @@ -60,6 +62,7 @@ export function setupSavedObjects( }; }, }, + modelVersions: connectorModelVersions, }); // Encrypted attributes @@ -94,6 +97,7 @@ export function setupSavedObjects( }, }; }, + modelVersions: actionTaskParamsModelVersions, }); encryptedSavedObjects.registerType({ type: ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, diff --git a/x-pack/plugins/actions/server/saved_objects/model_versions/action_task_params_model_versions.ts b/x-pack/plugins/actions/server/saved_objects/model_versions/action_task_params_model_versions.ts new file mode 100644 index 00000000000000..570ebff743c172 --- /dev/null +++ b/x-pack/plugins/actions/server/saved_objects/model_versions/action_task_params_model_versions.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 { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; +import { actionTaskParamsSchemaV1 } from '../schemas/action_task_params'; + +export const actionTaskParamsModelVersions: SavedObjectsModelVersionMap = { + '1': { + changes: [], + schemas: { + create: actionTaskParamsSchemaV1, + }, + }, +}; diff --git a/x-pack/plugins/actions/server/saved_objects/model_versions/connector_model_versions.ts b/x-pack/plugins/actions/server/saved_objects/model_versions/connector_model_versions.ts new file mode 100644 index 00000000000000..03d305d26a0866 --- /dev/null +++ b/x-pack/plugins/actions/server/saved_objects/model_versions/connector_model_versions.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 { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; +import { rawConnectorSchemaV1 } from '../schemas/raw_connector'; + +export const connectorModelVersions: SavedObjectsModelVersionMap = { + '1': { + changes: [], + schemas: { + create: rawConnectorSchemaV1, + }, + }, +}; diff --git a/x-pack/plugins/actions/server/saved_objects/model_versions/index.ts b/x-pack/plugins/actions/server/saved_objects/model_versions/index.ts new file mode 100644 index 00000000000000..fdfc6adecd8e01 --- /dev/null +++ b/x-pack/plugins/actions/server/saved_objects/model_versions/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { connectorModelVersions } from './connector_model_versions'; +export { actionTaskParamsModelVersions } from './action_task_params_model_versions'; diff --git a/x-pack/plugins/actions/server/saved_objects/schemas/action_task_params/index.ts b/x-pack/plugins/actions/server/saved_objects/schemas/action_task_params/index.ts new file mode 100644 index 00000000000000..4ce0e679adf5e4 --- /dev/null +++ b/x-pack/plugins/actions/server/saved_objects/schemas/action_task_params/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 { actionTaskParamsSchema as actionTaskParamsSchemaV1 } from './v1'; diff --git a/x-pack/plugins/actions/server/saved_objects/schemas/action_task_params/v1.ts b/x-pack/plugins/actions/server/saved_objects/schemas/action_task_params/v1.ts new file mode 100644 index 00000000000000..ceef18ae2dd75c --- /dev/null +++ b/x-pack/plugins/actions/server/saved_objects/schemas/action_task_params/v1.ts @@ -0,0 +1,29 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +export const actionTaskParamsSchema = schema.object({ + actionId: schema.string(), + executionId: schema.maybe(schema.string()), + apiKey: schema.nullable(schema.string()), + params: schema.recordOf(schema.string(), schema.maybe(schema.any()), { defaultValue: {} }), + consumer: schema.maybe(schema.string()), + source: schema.maybe(schema.string()), + relatedSavedObjects: schema.maybe( + schema.arrayOf( + schema.object({ + namespace: schema.maybe(schema.string({ minLength: 1 })), + id: schema.string({ minLength: 1 }), + type: schema.string({ minLength: 1 }), + // optional; for SO types like action/alert that have type id's + typeId: schema.maybe(schema.string({ minLength: 1 })), + }), + { defaultValue: [] } + ) + ), +}); diff --git a/x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/index.ts b/x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/index.ts new file mode 100644 index 00000000000000..f86d616c033936 --- /dev/null +++ b/x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/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 { rawConnectorSchema as rawConnectorSchemaV1 } from './v1'; diff --git a/x-pack/plugins/actions/server/raw_connector_schema.test.ts b/x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/v1.test.ts similarity index 93% rename from x-pack/plugins/actions/server/raw_connector_schema.test.ts rename to x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/v1.test.ts index 80c8ba0cfef7c1..ed2fe6b3a371cc 100644 --- a/x-pack/plugins/actions/server/raw_connector_schema.test.ts +++ b/x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/v1.test.ts @@ -5,18 +5,18 @@ * 2.0. */ -import { rawConnectorSchema } from './raw_connector_schema'; +import { rawConnectorSchema } from './v1'; const action = { actionTypeId: '12345', name: 'test-action-name', - isMissingSecrets: true, + isMissingSecrets: false, config: { foo: 'bar', }, - secrets: { + secrets: JSON.stringify({ pass: 'foo', - }, + }), isPreconfigured: false, isSystemAction: false, }; diff --git a/x-pack/plugins/actions/server/raw_connector_schema.ts b/x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/v1.ts similarity index 73% rename from x-pack/plugins/actions/server/raw_connector_schema.ts rename to x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/v1.ts index e98b31aef177f4..df1927972af897 100644 --- a/x-pack/plugins/actions/server/raw_connector_schema.ts +++ b/x-pack/plugins/actions/server/saved_objects/schemas/raw_connector/v1.ts @@ -11,8 +11,10 @@ export const rawConnectorSchema = schema.object({ actionTypeId: schema.string(), name: schema.string(), isMissingSecrets: schema.boolean(), - config: schema.recordOf(schema.string(), schema.any()), - secrets: schema.recordOf(schema.string(), schema.any()), + config: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + // Encrypted fields are saved as string. Decrypted version of the 'secrets' field is an object + secrets: schema.string({ defaultValue: '{}' }), + isPreconfigured: schema.maybe(schema.boolean()), isSystemAction: schema.maybe(schema.boolean()), id: schema.maybe(schema.string()), diff --git a/x-pack/plugins/alerting/server/lib/create_get_alert_indices_alias.test.ts b/x-pack/plugins/alerting/server/lib/create_get_alert_indices_alias.test.ts index 32fac87b7485ba..9a8109977962c0 100644 --- a/x-pack/plugins/alerting/server/lib/create_get_alert_indices_alias.test.ts +++ b/x-pack/plugins/alerting/server/lib/create_get_alert_indices_alias.test.ts @@ -33,7 +33,6 @@ describe('createGetAlertIndicesAliasFn', () => { licensing: licensingMock.createSetup(), minimumScheduleInterval: { value: '1m', enforce: false }, inMemoryMetrics, - latestRuleVersion: 1, }; const registry = new RuleTypeRegistry(ruleTypeRegistryParams); registry.register({ diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 884fa761526ea2..1eb130f523c9cc 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -79,7 +79,6 @@ import { registerAlertingUsageCollector } from './usage'; import { initializeAlertingTelemetry, scheduleAlertingTelemetry } from './usage/task'; import { setupSavedObjects, - getLatestRuleVersion, RULE_SAVED_OBJECT_TYPE, AD_HOC_RUN_SAVED_OBJECT_TYPE, } from './saved_objects'; @@ -333,7 +332,6 @@ export class AlertingPlugin { alertsService: this.alertsService, minimumScheduleInterval: this.config.rules.minimumScheduleInterval, inMemoryMetrics: this.inMemoryMetrics, - latestRuleVersion: getLatestRuleVersion(), }); this.ruleTypeRegistry = ruleTypeRegistry; diff --git a/x-pack/plugins/alerting/server/rule_type_registry.mock.ts b/x-pack/plugins/alerting/server/rule_type_registry.mock.ts index 0aa7e5b68b40cf..706484fdd92f64 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.mock.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.mock.ts @@ -18,7 +18,6 @@ const createRuleTypeRegistryMock = () => { list: jest.fn(), getAllTypes: jest.fn(), ensureRuleTypeEnabled: jest.fn(), - getLatestRuleVersion: jest.fn(), }; return mocked; }; 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 2059f1e7548e62..709533bb898f2f 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -40,7 +40,6 @@ beforeEach(() => { licensing: licensingMock.createSetup(), minimumScheduleInterval: { value: '1m', enforce: false }, inMemoryMetrics, - latestRuleVersion: 1, }; }); @@ -913,16 +912,6 @@ describe('Create Lifecycle', () => { ).toThrowErrorMatchingInlineSnapshot(`"Fail"`); }); }); - - describe('getLatestRuleVersion', () => { - test('should return the latest rule version', async () => { - const ruleTypeRegistry = new RuleTypeRegistry({ - ...ruleTypeRegistryParams, - latestRuleVersion: 5, - }); - expect(ruleTypeRegistry.getLatestRuleVersion()).toBe(5); - }); - }); }); function ruleTypeWithVariables( diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index 79c959a62eedf4..50ab1f113ab8b7 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -50,7 +50,6 @@ export interface ConstructorOptions { minimumScheduleInterval: AlertingRulesConfig['minimumScheduleInterval']; inMemoryMetrics: InMemoryMetrics; alertsService: AlertsService | null; - latestRuleVersion: number; } export interface RegistryRuleType @@ -160,7 +159,6 @@ export class RuleTypeRegistry { private readonly licensing: LicensingPluginSetup; private readonly inMemoryMetrics: InMemoryMetrics; private readonly alertsService: AlertsService | null; - private readonly latestRuleVersion: number; constructor({ config, @@ -172,7 +170,6 @@ export class RuleTypeRegistry { minimumScheduleInterval, inMemoryMetrics, alertsService, - latestRuleVersion, }: ConstructorOptions) { this.config = config; this.logger = logger; @@ -183,7 +180,6 @@ export class RuleTypeRegistry { this.minimumScheduleInterval = minimumScheduleInterval; this.inMemoryMetrics = inMemoryMetrics; this.alertsService = alertsService; - this.latestRuleVersion = latestRuleVersion; } public has(id: string) { @@ -436,10 +432,6 @@ export class RuleTypeRegistry { public getAllTypes(): string[] { return [...this.ruleTypes.keys()]; } - - public getLatestRuleVersion() { - return this.latestRuleVersion; - } } function normalizedActionVariables(actionVariables: RuleType['actionVariables']) { diff --git a/x-pack/plugins/alerting/server/saved_objects/ad_hoc_run_params_model_versions.ts b/x-pack/plugins/alerting/server/saved_objects/ad_hoc_run_params_model_versions.ts deleted file mode 100644 index 10d8dc759e9be1..00000000000000 --- a/x-pack/plugins/alerting/server/saved_objects/ad_hoc_run_params_model_versions.ts +++ /dev/null @@ -1,51 +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 { - SavedObjectsModelVersion, - SavedObjectsModelVersionMap, -} from '@kbn/core-saved-objects-server'; -import { AdHocRunSO } from '../data/ad_hoc_run/types'; -import { rawAdHocRunParamsSchemaV1 } from './schemas/raw_ad_hoc_run_params'; - -interface CustomSavedObjectsModelVersion extends SavedObjectsModelVersion { - isCompatibleWithPreviousVersion: (param: AdHocRunSO) => boolean; -} - -export interface CustomSavedObjectsModelVersionMap extends SavedObjectsModelVersionMap { - [modelVersion: string]: CustomSavedObjectsModelVersion; -} - -export const adHocRunParamsModelVersions: CustomSavedObjectsModelVersionMap = { - '1': { - changes: [], - schemas: { - forwardCompatibility: rawAdHocRunParamsSchemaV1.extends({}, { unknowns: 'ignore' }), - create: rawAdHocRunParamsSchemaV1, - }, - isCompatibleWithPreviousVersion: () => true, - }, -}; - -export const getLatestAdHocRunParamsVersion = () => - Math.max(...Object.keys(adHocRunParamsModelVersions).map(Number)); - -export function getMinimumCompatibleVersion( - modelVersions: CustomSavedObjectsModelVersionMap, - version: number, - adHocRunParam: AdHocRunSO -): number { - if (version === 1) { - return 1; - } - - if (modelVersions[version].isCompatibleWithPreviousVersion(adHocRunParam)) { - return getMinimumCompatibleVersion(modelVersions, version - 1, adHocRunParam); - } - - return version; -} diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts index 0dd261c4c39f1f..eb07a84950d14b 100644 --- a/x-pack/plugins/alerting/server/saved_objects/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -24,13 +24,11 @@ import { getImportWarnings } from './get_import_warnings'; import { isRuleExportable } from './is_rule_exportable'; import { RuleTypeRegistry } from '../rule_type_registry'; export { partiallyUpdateRule } from './partially_update_rule'; -export { getLatestRuleVersion, getMinimumCompatibleVersion } from './rule_model_versions'; import { RULES_SETTINGS_SAVED_OBJECT_TYPE, MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE, } from '../../common'; -import { ruleModelVersions } from './rule_model_versions'; -import { adHocRunParamsModelVersions } from './ad_hoc_run_params_model_versions'; +import { ruleModelVersions, adHocRunParamsModelVersions } from './model_versions'; export const RULE_SAVED_OBJECT_TYPE = 'alert'; export const AD_HOC_RUN_SAVED_OBJECT_TYPE = 'ad_hoc_run_params'; diff --git a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts index 7ed188915c869c..27145ecfe072fc 100644 --- a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts @@ -38,7 +38,6 @@ beforeEach(() => { licensing: licensingMock.createSetup(), minimumScheduleInterval: { value: '1m', enforce: false }, inMemoryMetrics, - latestRuleVersion: 1, }; }); diff --git a/x-pack/plugins/alerting/server/saved_objects/model_versions/ad_hoc_run_params_model_versions.ts b/x-pack/plugins/alerting/server/saved_objects/model_versions/ad_hoc_run_params_model_versions.ts new file mode 100644 index 00000000000000..95f544be5c8e2c --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/model_versions/ad_hoc_run_params_model_versions.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 { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; +import { rawAdHocRunParamsSchemaV1 } from '../schemas/raw_ad_hoc_run_params'; + +export const adHocRunParamsModelVersions: SavedObjectsModelVersionMap = { + '1': { + changes: [], + schemas: { + forwardCompatibility: rawAdHocRunParamsSchemaV1.extends({}, { unknowns: 'ignore' }), + create: rawAdHocRunParamsSchemaV1, + }, + }, +}; diff --git a/x-pack/plugins/alerting/server/saved_objects/model_versions/index.ts b/x-pack/plugins/alerting/server/saved_objects/model_versions/index.ts new file mode 100644 index 00000000000000..89c4f3a3cd2bb4 --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/model_versions/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { adHocRunParamsModelVersions } from './ad_hoc_run_params_model_versions'; +export { ruleModelVersions } from './rule_model_versions'; diff --git a/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts b/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.ts new file mode 100644 index 00000000000000..2d778667d2b79f --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/model_versions/rule_model_versions.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 { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; +import { rawRuleSchemaV1 } from '../schemas/raw_rule'; + +export const ruleModelVersions: SavedObjectsModelVersionMap = { + '1': { + changes: [], + schemas: { + create: rawRuleSchemaV1, + }, + }, +}; diff --git a/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.test.ts b/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.test.ts deleted file mode 100644 index 9afcdaad8e2f4a..00000000000000 --- a/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.test.ts +++ /dev/null @@ -1,77 +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 { - CustomSavedObjectsModelVersionMap, - getLatestRuleVersion, - getMinimumCompatibleVersion, -} from './rule_model_versions'; -import { schema } from '@kbn/config-schema'; -import { RawRule } from '../types'; - -describe('rule model versions', () => { - const ruleModelVersions: CustomSavedObjectsModelVersionMap = { - '1': { - changes: [], - schemas: { - create: schema.object({ - name: schema.string(), - }), - }, - isCompatibleWithPreviousVersion: (rawRule) => true, - }, - '2': { - changes: [], - schemas: { - create: schema.object({ - name: schema.string(), - }), - }, - isCompatibleWithPreviousVersion: (rawRule) => false, - }, - '3': { - changes: [], - schemas: { - create: schema.object({ - name: schema.string(), - }), - }, - isCompatibleWithPreviousVersion: (rawRule) => rawRule.name === 'test', - }, - '4': { - changes: [], - schemas: { - create: schema.object({ - name: schema.string(), - }), - }, - isCompatibleWithPreviousVersion: (rawRule) => rawRule.name === 'test', - }, - }; - - const rawRule = { name: 'test' } as RawRule; - const mismatchingRawRule = { enabled: true } as RawRule; - - describe('getMinimumCompatibleVersion', () => { - it('should return the minimum compatible version for the matching rawRule', () => { - expect(getMinimumCompatibleVersion(ruleModelVersions, 1, rawRule)).toBe(1); - expect(getMinimumCompatibleVersion(ruleModelVersions, 2, rawRule)).toBe(2); - expect(getMinimumCompatibleVersion(ruleModelVersions, 3, rawRule)).toBe(2); - expect(getMinimumCompatibleVersion(ruleModelVersions, 4, rawRule)).toBe(2); - }); - it('should return the minimum compatible version for the mismatching rawRule', () => { - expect(getMinimumCompatibleVersion(ruleModelVersions, 3, mismatchingRawRule)).toBe(3); - expect(getMinimumCompatibleVersion(ruleModelVersions, 4, mismatchingRawRule)).toBe(4); - }); - }); - - describe('getLatestRuleVersion', () => { - it('should return the latest rule model version', () => { - expect(getLatestRuleVersion()).toBe(1); - }); - }); -}); diff --git a/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.ts b/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.ts deleted file mode 100644 index 38adc17389b233..00000000000000 --- a/x-pack/plugins/alerting/server/saved_objects/rule_model_versions.ts +++ /dev/null @@ -1,49 +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 { - SavedObjectsModelVersion, - SavedObjectsModelVersionMap, -} from '@kbn/core-saved-objects-server'; -import { RawRule } from '../types'; -import { rawRuleSchemaV1 } from './schemas/raw_rule'; - -interface CustomSavedObjectsModelVersion extends SavedObjectsModelVersion { - isCompatibleWithPreviousVersion: (param: RawRule) => boolean; -} - -export interface CustomSavedObjectsModelVersionMap extends SavedObjectsModelVersionMap { - [modelVersion: string]: CustomSavedObjectsModelVersion; -} - -export const ruleModelVersions: CustomSavedObjectsModelVersionMap = { - '1': { - changes: [], - schemas: { - create: rawRuleSchemaV1, - }, - isCompatibleWithPreviousVersion: (rawRule) => true, - }, -}; - -export const getLatestRuleVersion = () => Math.max(...Object.keys(ruleModelVersions).map(Number)); - -export function getMinimumCompatibleVersion( - modelVersions: CustomSavedObjectsModelVersionMap, - version: number, - rawRule: RawRule -): number { - if (version === 1) { - return 1; - } - - if (modelVersions[version].isCompatibleWithPreviousVersion(rawRule)) { - return getMinimumCompatibleVersion(modelVersions, version - 1, rawRule); - } - - return version; -} diff --git a/x-pack/plugins/task_manager/server/saved_objects/index.ts b/x-pack/plugins/task_manager/server/saved_objects/index.ts index 390990bd10dbf3..68bc796d7aba31 100644 --- a/x-pack/plugins/task_manager/server/saved_objects/index.ts +++ b/x-pack/plugins/task_manager/server/saved_objects/index.ts @@ -7,12 +7,12 @@ import type { SavedObjectsServiceSetup } from '@kbn/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { taskModelVersions } from './task_model_versions'; import { taskMappings } from './mappings'; import { getMigrations } from './migrations'; import { TaskManagerConfig } from '../config'; import { getOldestIdleActionTask } from '../queries/oldest_idle_action_task'; import { TASK_MANAGER_INDEX } from '../constants'; +import { taskModelVersions } from './model_versions'; export function setupSavedObjects( savedObjects: SavedObjectsServiceSetup, diff --git a/x-pack/plugins/task_manager/server/saved_objects/model_versions/index.ts b/x-pack/plugins/task_manager/server/saved_objects/model_versions/index.ts new file mode 100644 index 00000000000000..9d84e528a3d398 --- /dev/null +++ b/x-pack/plugins/task_manager/server/saved_objects/model_versions/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 { taskModelVersions } from './task_model_versions'; diff --git a/x-pack/plugins/task_manager/server/saved_objects/task_model_versions.ts b/x-pack/plugins/task_manager/server/saved_objects/model_versions/task_model_versions.ts similarity index 92% rename from x-pack/plugins/task_manager/server/saved_objects/task_model_versions.ts rename to x-pack/plugins/task_manager/server/saved_objects/model_versions/task_model_versions.ts index adfebecf84dcee..d76d26e56c23e3 100644 --- a/x-pack/plugins/task_manager/server/saved_objects/task_model_versions.ts +++ b/x-pack/plugins/task_manager/server/saved_objects/model_versions/task_model_versions.ts @@ -6,7 +6,7 @@ */ import { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; -import { taskSchemaV1 } from './schemas/task'; +import { taskSchemaV1 } from '../schemas/task'; export const taskModelVersions: SavedObjectsModelVersionMap = { '1': { From c49cfbea81f36abca2a04d32d8a4ad14585ef6bb Mon Sep 17 00:00:00 2001 From: Nikita Indik Date: Tue, 18 Jun 2024 16:41:16 +0200 Subject: [PATCH 033/123] [Security Solution] `DetectionRulesClient`: return `RuleResponse` from `createCustomRule` and `createPrebuiltRule` (#185748) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Partially addresses: https://github.com/elastic/kibana/issues/184364** ## Summary This PR changes `createCustomRule` and `createPrebuiltRule` methods to return `RuleResponse` instead of `RuleAlertType`. This is a continuation of the effort to improve `DetectionRulesClient`. As a part of it we want to make the client return `RuleResponse` from all its public methods. This is good because it lets us hide rule's internal structure and centralise conversions in one place – in the client. So in this and upcoming PRs we are going to convert `RuleAlertType` to `RuleResponse` within the client's methods and return the `RuleResponse` object. --- .../perform_rule_installation_route.ts | 3 +- .../rule_objects/create_prebuilt_rules.ts | 2 +- .../lib/detection_engine/routes/utils.test.ts | 19 +++++++++ .../lib/detection_engine/routes/utils.ts | 7 ++++ .../api/rules/bulk_create_rules/route.test.ts | 5 +-- .../api/rules/bulk_create_rules/route.ts | 4 +- .../api/rules/create_rule/route.test.ts | 5 +-- .../api/rules/create_rule/route.ts | 4 +- ...on_rules_client.create_custom_rule.test.ts | 21 ++++++++++ ..._rules_client.create_prebuilt_rule.test.ts | 39 +++++++++++-------- .../detection_rules_client.ts | 5 ++- .../detection_rules_client_interface.ts | 23 ++++++----- .../methods/create_custom_rule.ts | 22 ++++++++--- .../methods/create_prebuilt_rule.ts | 28 +++++++++---- .../logic/detection_rules_client/utils.ts | 19 +++++++++ 15 files changed, 149 insertions(+), 57 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_installation/perform_rule_installation_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_installation/perform_rule_installation_route.ts index 0399d3312de2f3..8ffec60a26c119 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_installation/perform_rule_installation_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_installation/perform_rule_installation_route.ts @@ -19,7 +19,6 @@ import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { buildRouteValidation } from '../../../../../utils/build_validation/route_validation'; import type { PromisePoolError } from '../../../../../utils/promise_pool'; import { buildSiemResponse } from '../../../routes/utils'; -import { internalRuleToAPIResponse } from '../../../rule_management/normalization/rule_converters'; import { aggregatePrebuiltRuleErrors } from '../../logic/aggregate_prebuilt_rule_errors'; import { ensureLatestRulesPackageInstalled } from '../../logic/ensure_latest_rules_package_installed'; import { createPrebuiltRuleAssetsClient } from '../../logic/rule_assets/prebuilt_rule_assets_client'; @@ -135,7 +134,7 @@ export const performRuleInstallationRoute = (router: SecuritySolutionPluginRoute failed: ruleErrors.length, }, results: { - created: installedRules.map(({ result }) => internalRuleToAPIResponse(result)), + created: installedRules.map(({ result }) => result), skipped: skippedRules, }, errors: allErrors, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_objects/create_prebuilt_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_objects/create_prebuilt_rules.ts index 8da1055156d3d3..4f6d3b8314aa5d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_objects/create_prebuilt_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_objects/create_prebuilt_rules.ts @@ -21,7 +21,7 @@ export const createPrebuiltRules = ( items: rules, executor: async (rule) => { return detectionRulesClient.createPrebuiltRule({ - ruleAsset: rule, + params: rule, }); }, }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts index da0bc90c9e4df4..cbc3e006a4fea9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts @@ -10,6 +10,7 @@ import type { BulkError } from './utils'; import { transformBulkError, convertToSnakeCase, SiemResponseFactory } from './utils'; import { responseMock } from './__mocks__'; import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; +import { RuleResponseValidationError } from '../rule_management/logic/detection_rules_client/utils'; describe('utils', () => { describe('transformBulkError', () => { @@ -59,6 +60,24 @@ describe('utils', () => { }; expect(transformed).toEqual(expected); }); + + test('it detects a RuleResponseValidationError and returns an error status of 500', () => { + const error = new RuleResponseValidationError({ + ruleId: 'rule-1', + message: 'name: Required', + }); + + const expected: BulkError = { + rule_id: 'rule-1', + error: { message: 'name: Required', status_code: 500 }, + }; + + /* Works when the ruleId is passed in. For example, when creating a rule with a user-set ruleId */ + expect(transformBulkError('rule-1', error)).toEqual(expected); + + /* Works when the ruleId is not passed in. For example, when creating a rule with a generated ruleId */ + expect(transformBulkError(undefined, error)).toEqual(expected); + }); }); describe('convertToSnakeCase', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts index 5b0e8590525002..0e08374b1f9275 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts @@ -17,6 +17,7 @@ import type { } from '@kbn/core/server'; import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; +import { RuleResponseValidationError } from '../rule_management/logic/detection_rules_client/utils'; export interface OutputError { message: string; @@ -116,6 +117,12 @@ export const transformBulkError = ( statusCode: 400, message: err.message, }); + } else if (err instanceof RuleResponseValidationError) { + return createBulkErrorObject({ + ruleId: err.ruleId, + statusCode: 500, + message: err.message, + }); } else { return createBulkErrorObject({ ruleId, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts index 21ee4116edc2c7..d6403f0d1553de 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts @@ -22,6 +22,7 @@ import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-m import { getQueryRuleParams } from '../../../../rule_schema/mocks'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { HttpAuthzError } from '../../../../../machine_learning/validation'; +import { getRulesSchemaMock } from '../../../../../../../common/api/detection_engine/model/rule_schema/rule_response_schema.mock'; describe('Bulk create rules route', () => { let server: ReturnType; @@ -34,9 +35,7 @@ describe('Bulk create rules route', () => { clients.rulesClient.find.mockResolvedValue(getEmptyFindResult()); // no existing rules clients.rulesClient.create.mockResolvedValue(getRuleMock(getQueryRuleParams())); // successful creation - clients.detectionRulesClient.createCustomRule.mockResolvedValue( - getRuleMock(getQueryRuleParams()) - ); + clients.detectionRulesClient.createCustomRule.mockResolvedValue(getRulesSchemaMock()); context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse()) ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts index a8e5a0446c6e3f..ba6eebce2207c8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts @@ -18,7 +18,6 @@ import { import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import { readRules } from '../../../logic/detection_rules_client/read_rules'; import { getDuplicates } from './get_duplicates'; -import { transformValidateBulkError } from '../../../utils/validate'; import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { validateRuleDefaultExceptionList } from '../../../logic/exceptions/validate_rule_default_exception_list'; import { validateRulesWithDuplicatedDefaultExceptionsList } from '../../../logic/exceptions/validate_rules_with_duplicated_default_exceptions_list'; @@ -113,7 +112,7 @@ export const bulkCreateRulesRoute = (router: SecuritySolutionPluginRouter, logge params: payloadRule, }); - return transformValidateBulkError(createdRule.params.ruleId, createdRule); + return createdRule; } catch (err) { return transformBulkError( payloadRule.rule_id, @@ -122,6 +121,7 @@ export const bulkCreateRulesRoute = (router: SecuritySolutionPluginRouter, logge } }) ); + const rulesBulk = [ ...rules, ...dupes.map((ruleId) => diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts index 08a9f4e6c47694..1402518103e64e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts @@ -20,6 +20,7 @@ import { getCreateRulesSchemaMock } from '../../../../../../../common/api/detect import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { getQueryRuleParams } from '../../../../rule_schema/mocks'; import { HttpAuthzError } from '../../../../../machine_learning/validation'; +import { getRulesSchemaMock } from '../../../../../../../common/api/detection_engine/model/rule_schema/rule_response_schema.mock'; describe('Create rule route', () => { let server: ReturnType; @@ -31,9 +32,7 @@ describe('Create rule route', () => { clients.rulesClient.find.mockResolvedValue(getEmptyFindResult()); // no current rules clients.rulesClient.create.mockResolvedValue(getRuleMock(getQueryRuleParams())); // creation succeeds - clients.detectionRulesClient.createCustomRule.mockResolvedValue( - getRuleMock(getQueryRuleParams()) - ); + clients.detectionRulesClient.createCustomRule.mockResolvedValue(getRulesSchemaMock()); context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise(getBasicEmptySearchResponse()) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts index 03642aa12266b2..3819154c1b8a3c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts @@ -19,7 +19,7 @@ import { buildSiemResponse } from '../../../../routes/utils'; import { readRules } from '../../../logic/detection_rules_client/read_rules'; import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list'; import { validateRuleDefaultExceptionList } from '../../../logic/exceptions/validate_rule_default_exception_list'; -import { transformValidate, validateResponseActionsPermissions } from '../../../utils/validate'; +import { validateResponseActionsPermissions } from '../../../utils/validate'; export const createRuleRoute = (router: SecuritySolutionPluginRouter): void => { router.versioned @@ -94,7 +94,7 @@ export const createRuleRoute = (router: SecuritySolutionPluginRouter): void => { }); return response.ok({ - body: transformValidate(createdRule), + body: createdRule, }); } catch (err) { const error = transformError(err as Error); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.create_custom_rule.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.create_custom_rule.test.ts index a8335108d7cbeb..1cf4afecedb26d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.create_custom_rule.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.create_custom_rule.test.ts @@ -12,11 +12,15 @@ import { getCreateMachineLearningRulesSchemaMock, getCreateThreatMatchRulesSchemaMock, } from '../../../../../../common/api/detection_engine/model/rule_schema/mocks'; +import { getRuleMock } from '../../../routes/__mocks__/request_responses'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../../common/constants'; import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; import { createDetectionRulesClient } from './detection_rules_client'; import type { IDetectionRulesClient } from './detection_rules_client_interface'; +import { RuleResponseValidationError } from './utils'; +import type { RuleAlertType } from '../../../rule_schema'; jest.mock('../../../../machine_learning/authz'); jest.mock('../../../../machine_learning/validation'); @@ -29,7 +33,10 @@ describe('DetectionRulesClient.createCustomRule', () => { beforeEach(() => { jest.resetAllMocks(); + rulesClient = rulesClientMock.create(); + rulesClient.create.mockResolvedValue(getRuleMock(getQueryRuleParams())); + detectionRulesClient = createDetectionRulesClient(rulesClient, mlAuthz); }); @@ -63,6 +70,20 @@ describe('DetectionRulesClient.createCustomRule', () => { expect(rulesClient.create).not.toHaveBeenCalled(); }); + it('throws if RuleResponse validation fails', async () => { + const internalRuleMock: RuleAlertType = getRuleMock({ + ...getQueryRuleParams(), + /* Casting as 'query' suppress to TS error */ + type: 'fake-non-existent-type' as 'query', + }); + + rulesClient.create.mockResolvedValueOnce(internalRuleMock); + + await expect( + detectionRulesClient.createCustomRule({ params: getCreateMachineLearningRulesSchemaMock() }) + ).rejects.toThrow(RuleResponseValidationError); + }); + it('calls the rulesClient with legacy ML params', async () => { await detectionRulesClient.createCustomRule({ params: getCreateMachineLearningRulesSchemaMock(), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.create_prebuilt_rule.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.create_prebuilt_rule.test.ts index d2a61dcc65e45b..fd3ac991a968fe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.create_prebuilt_rule.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.create_prebuilt_rule.test.ts @@ -12,6 +12,8 @@ import { getCreateMachineLearningRulesSchemaMock, getCreateThreatMatchRulesSchemaMock, } from '../../../../../../common/api/detection_engine/model/rule_schema/mocks'; +import { getRuleMock } from '../../../routes/__mocks__/request_responses'; +import { getQueryRuleParams } from '../../../rule_schema/mocks'; import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../../common/constants'; import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; @@ -29,22 +31,25 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { beforeEach(() => { jest.resetAllMocks(); + rulesClient = rulesClientMock.create(); + rulesClient.create.mockResolvedValue(getRuleMock(getQueryRuleParams())); + detectionRulesClient = createDetectionRulesClient(rulesClient, mlAuthz); }); it('creates a rule with the correct parameters and options', async () => { - const ruleAsset = { ...getCreateRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; + const params = { ...getCreateRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; - await detectionRulesClient.createPrebuiltRule({ ruleAsset }); + await detectionRulesClient.createPrebuiltRule({ params }); expect(rulesClient.create).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ enabled: false, - name: ruleAsset.name, + name: params.name, params: expect.objectContaining({ - ruleId: ruleAsset.rule_id, + ruleId: params.rule_id, immutable: true, }), }), @@ -53,12 +58,12 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { }); it('throws if mlAuth fails', async () => { - const ruleAsset = { ...getCreateRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; + const params = { ...getCreateRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; (throwAuthzError as jest.Mock).mockImplementationOnce(() => { throw new Error('mocked MLAuth error'); }); - await expect(detectionRulesClient.createPrebuiltRule({ ruleAsset })).rejects.toThrow( + await expect(detectionRulesClient.createPrebuiltRule({ params })).rejects.toThrow( 'mocked MLAuth error' ); @@ -66,13 +71,13 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { }); it('calls the rulesClient with legacy ML params', async () => { - const ruleAsset = { + const params = { ...getCreateMachineLearningRulesSchemaMock(), version: 1, rule_id: 'rule-id', }; await detectionRulesClient.createPrebuiltRule({ - ruleAsset, + params, }); expect(rulesClient.create).toHaveBeenCalledWith( @@ -80,8 +85,8 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { data: expect.objectContaining({ enabled: false, params: expect.objectContaining({ - anomalyThreshold: ruleAsset.anomaly_threshold, - machineLearningJobId: [ruleAsset.machine_learning_job_id], + anomalyThreshold: params.anomaly_threshold, + machineLearningJobId: [params.machine_learning_job_id], immutable: true, }), }), @@ -90,14 +95,14 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { }); it('calls the rulesClient with ML params', async () => { - const ruleAsset = { + const params = { ...getCreateMachineLearningRulesSchemaMock(), machine_learning_job_id: ['new_job_1', 'new_job_2'], version: 1, rule_id: 'rule-id', }; await detectionRulesClient.createPrebuiltRule({ - ruleAsset, + params, }); expect(rulesClient.create).toHaveBeenCalledWith( @@ -115,11 +120,11 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { }); it('populates a threatIndicatorPath value for threat_match rule if empty', async () => { - const ruleAsset = { ...getCreateThreatMatchRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; - delete ruleAsset.threat_indicator_path; + const params = { ...getCreateThreatMatchRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; + delete params.threat_indicator_path; await detectionRulesClient.createPrebuiltRule({ - ruleAsset, + params, }); expect(rulesClient.create).toHaveBeenCalledWith( @@ -136,8 +141,8 @@ describe('DetectionRulesClient.createPrebuiltRule', () => { }); it('does not populate a threatIndicatorPath value for other rules if empty', async () => { - const ruleAsset = { ...getCreateRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; - await detectionRulesClient.createPrebuiltRule({ ruleAsset }); + const params = { ...getCreateRulesSchemaMock(), version: 1, rule_id: 'rule-id' }; + await detectionRulesClient.createPrebuiltRule({ params }); expect(rulesClient.create).not.toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.ts index 7256441697e655..c26649604b2820 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client.ts @@ -9,6 +9,7 @@ import type { RulesClient } from '@kbn/alerting-plugin/server'; import type { MlAuthz } from '../../../../machine_learning/authz'; import type { RuleAlertType } from '../../../rule_schema'; +import type { RuleResponse } from '../../../../../../common/api/detection_engine/model/rule_schema'; import type { IDetectionRulesClient, CreateCustomRuleArgs, @@ -34,13 +35,13 @@ export const createDetectionRulesClient = ( rulesClient: RulesClient, mlAuthz: MlAuthz ): IDetectionRulesClient => ({ - async createCustomRule(args: CreateCustomRuleArgs): Promise { + async createCustomRule(args: CreateCustomRuleArgs): Promise { return withSecuritySpan('DetectionRulesClient.createCustomRule', async () => { return createCustomRule(rulesClient, args, mlAuthz); }); }, - async createPrebuiltRule(args: CreatePrebuiltRuleArgs): Promise { + async createPrebuiltRule(args: CreatePrebuiltRuleArgs): Promise { return withSecuritySpan('DetectionRulesClient.createPrebuiltRule', async () => { return createPrebuiltRule(rulesClient, args, mlAuthz); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client_interface.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client_interface.ts index d99b0b9c2cbd05..2d9c787119cdff 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client_interface.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/detection_rules_client_interface.ts @@ -5,26 +5,25 @@ * 2.0. */ -import type { RuleCreateProps } from '../../../../../../common/api/detection_engine/model/rule_schema'; -import type { PrebuiltRuleAsset } from '../../../prebuilt_rules'; import type { + RuleCreateProps, RuleUpdateProps, RulePatchProps, RuleObjectId, RuleToImport, + RuleResponse, } from '../../../../../../common/api/detection_engine'; import type { RuleAlertType } from '../../../rule_schema'; +import type { PrebuiltRuleAsset } from '../../../prebuilt_rules'; export interface IDetectionRulesClient { - createCustomRule: (createCustomRulePayload: CreateCustomRuleArgs) => Promise; - createPrebuiltRule: (createPrebuiltRulePayload: CreatePrebuiltRuleArgs) => Promise; - updateRule: (updateRulePayload: UpdateRuleArgs) => Promise; - patchRule: (patchRulePayload: PatchRuleArgs) => Promise; - deleteRule: (deleteRulePayload: DeleteRuleArgs) => Promise; - upgradePrebuiltRule: ( - upgradePrebuiltRulePayload: UpgradePrebuiltRuleArgs - ) => Promise; - importRule: (importRulePayload: ImportRuleArgs) => Promise; + createCustomRule: (args: CreateCustomRuleArgs) => Promise; + createPrebuiltRule: (args: CreatePrebuiltRuleArgs) => Promise; + updateRule: (args: UpdateRuleArgs) => Promise; + patchRule: (args: PatchRuleArgs) => Promise; + deleteRule: (args: DeleteRuleArgs) => Promise; + upgradePrebuiltRule: (args: UpgradePrebuiltRuleArgs) => Promise; + importRule: (args: ImportRuleArgs) => Promise; } export interface CreateCustomRuleArgs { @@ -32,7 +31,7 @@ export interface CreateCustomRuleArgs { } export interface CreatePrebuiltRuleArgs { - ruleAsset: PrebuiltRuleAsset; + params: RuleCreateProps; } export interface UpdateRuleArgs { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/create_custom_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/create_custom_rule.ts index c9b3b7b542a17f..c77446f5baf638 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/create_custom_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/create_custom_rule.ts @@ -6,18 +6,20 @@ */ import type { RulesClient } from '@kbn/alerting-plugin/server'; +import { stringifyZodError } from '@kbn/zod-helpers'; import type { CreateCustomRuleArgs } from '../detection_rules_client_interface'; import type { MlAuthz } from '../../../../../machine_learning/authz'; -import type { RuleAlertType, RuleParams } from '../../../../rule_schema'; +import type { RuleParams } from '../../../../rule_schema'; +import { RuleResponse } from '../../../../../../../common/api/detection_engine/model/rule_schema'; import { convertCreateAPIToInternalSchema } from '../../../normalization/rule_converters'; - -import { validateMlAuth } from '../utils'; +import { transform } from '../../../utils/utils'; +import { validateMlAuth, RuleResponseValidationError } from '../utils'; export const createCustomRule = async ( rulesClient: RulesClient, args: CreateCustomRuleArgs, mlAuthz: MlAuthz -): Promise => { +): Promise => { const { params } = args; await validateMlAuth(mlAuthz, params.type); @@ -26,5 +28,15 @@ export const createCustomRule = async ( data: internalRule, }); - return rule; + /* Trying to convert the rule to a RuleResponse object */ + const parseResult = RuleResponse.safeParse(transform(rule)); + + if (!parseResult.success) { + throw new RuleResponseValidationError({ + message: stringifyZodError(parseResult.error), + ruleId: rule.params.ruleId, + }); + } + + return parseResult.data; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/create_prebuilt_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/create_prebuilt_rule.ts index 0ada0197137a47..db510d9071c4f7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/create_prebuilt_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/methods/create_prebuilt_rule.ts @@ -6,23 +6,25 @@ */ import type { RulesClient } from '@kbn/alerting-plugin/server'; +import { stringifyZodError } from '@kbn/zod-helpers'; import type { CreatePrebuiltRuleArgs } from '../detection_rules_client_interface'; import type { MlAuthz } from '../../../../../machine_learning/authz'; -import type { RuleAlertType, RuleParams } from '../../../../rule_schema'; +import { RuleResponse } from '../../../../../../../common/api/detection_engine/model/rule_schema'; +import type { RuleParams } from '../../../../rule_schema'; import { convertCreateAPIToInternalSchema } from '../../../normalization/rule_converters'; - -import { validateMlAuth } from '../utils'; +import { transform } from '../../../utils/utils'; +import { validateMlAuth, RuleResponseValidationError } from '../utils'; export const createPrebuiltRule = async ( rulesClient: RulesClient, args: CreatePrebuiltRuleArgs, mlAuthz: MlAuthz -): Promise => { - const { ruleAsset } = args; +): Promise => { + const { params } = args; - await validateMlAuth(mlAuthz, ruleAsset.type); + await validateMlAuth(mlAuthz, params.type); - const internalRule = convertCreateAPIToInternalSchema(ruleAsset, { + const internalRule = convertCreateAPIToInternalSchema(params, { immutable: true, defaultEnabled: false, }); @@ -31,5 +33,15 @@ export const createPrebuiltRule = async ( data: internalRule, }); - return rule; + /* Trying to convert the rule to a RuleResponse object */ + const parseResult = RuleResponse.safeParse(transform(rule)); + + if (!parseResult.success) { + throw new RuleResponseValidationError({ + message: stringifyZodError(parseResult.error), + ruleId: rule.params.ruleId, + }); + } + + return parseResult.data; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/utils.ts index 0173ba5aea370c..624f86a49422ae 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/detection_rules_client/utils.ts @@ -5,12 +5,15 @@ * 2.0. */ +/* eslint-disable max-classes-per-file */ + import type { RulesClient } from '@kbn/alerting-plugin/server'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import type { MlAuthz } from '../../../../machine_learning/authz'; import type { RuleAlertType } from '../../../rule_schema'; +import type { RuleSignatureId } from '../../../../../../common/api/detection_engine/model/rule_schema/common_attributes.gen'; import { throwAuthzError } from '../../../../machine_learning/validation'; export const toggleRuleEnabledOnUpdate = async ( @@ -36,3 +39,19 @@ export class ClientError extends Error { this.statusCode = statusCode; } } + +/** + * Represents an error that occurred while validating a RuleResponse object. + * Includes the ruleId (rule signature id) of the rule that failed validation. + * Thrown when a rule does not match the RuleResponse schema. + * @param message - The error message + * @param ruleId - The rule signature id of the rule that failed validation + * @extends Error + */ +export class RuleResponseValidationError extends Error { + public readonly ruleId: RuleSignatureId; + constructor({ message, ruleId }: { message: string; ruleId: RuleSignatureId }) { + super(message); + this.ruleId = ruleId; + } +} From a0fb706e31d7a38d1a404040b5d7f2ccb4e60b11 Mon Sep 17 00:00:00 2001 From: Alexi Doak <109488926+doakalexi@users.noreply.github.com> Date: Tue, 18 Jun 2024 07:44:36 -0700 Subject: [PATCH 034/123] [ResponseOps] ES|QL rule type improvements - write query results to the alert doc (#184541) Resolves https://github.com/elastic/response-ops-team/issues/200 ## Summary This PR copies the fields from the ES|QL query results to the alert doc. Now that we are writing everything to the alert doc I removed the source fields selector from the ES|QL ui. ### Checklist - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### To verify - Create an ES Query ES|QL rule. - Go to [dev tools](http://localhost:5601/app/dev_tools#/console) and run the query below to verify that the query results are written to the alert doc. ``` GET .internal.alerts-stack.alerts-default*/_search ``` --- .../src/schemas/generated/stack_schema.ts | 3 +- .../public/rule_types/es_query/constants.ts | 1 - .../expression/esql_query_expression.tsx | 53 +++---------------- .../server/rule_types/constants.ts | 1 + .../es_query/lib/fetch_esql_query.test.ts | 28 +++++++++- .../es_query/lib/fetch_esql_query.ts | 22 +++++++- .../lib/parse_aggregation_results.test.ts | 6 +-- .../data/lib/parse_aggregation_results.ts | 4 +- .../builtin_alert_types/es_query/esql_only.ts | 14 +---- .../apis/maps/maps_telemetry.ts | 4 +- 10 files changed, 65 insertions(+), 71 deletions(-) diff --git a/packages/kbn-alerts-as-data-utils/src/schemas/generated/stack_schema.ts b/packages/kbn-alerts-as-data-utils/src/schemas/generated/stack_schema.ts index 94ba544e4c96f4..1d85ffcb1f7148 100644 --- a/packages/kbn-alerts-as-data-utils/src/schemas/generated/stack_schema.ts +++ b/packages/kbn-alerts-as-data-utils/src/schemas/generated/stack_schema.ts @@ -11,6 +11,7 @@ import * as rt from 'io-ts'; import { Either } from 'fp-ts/lib/Either'; import { AlertSchema } from './alert_schema'; +import { EcsSchema } from './ecs_schema'; const ISO_DATE_PATTERN = /^d{4}-d{2}-d{2}Td{2}:d{2}:d{2}.d{3}Z$/; export const IsoDateString = new rt.Type( 'IsoDateString', @@ -77,6 +78,6 @@ const StackAlertOptional = rt.partial({ }); // prettier-ignore -export const StackAlertSchema = rt.intersection([StackAlertRequired, StackAlertOptional, AlertSchema]); +export const StackAlertSchema = rt.intersection([StackAlertRequired, StackAlertOptional, AlertSchema, EcsSchema]); // prettier-ignore export type StackAlert = rt.TypeOf; diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/constants.ts b/x-pack/plugins/stack_alerts/public/rule_types/es_query/constants.ts index 7d01043bfbc214..e40f373cb95fc0 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/constants.ts +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/constants.ts @@ -22,7 +22,6 @@ export const DEFAULT_VALUES = { GROUP_BY: 'all', EXCLUDE_PREVIOUS_HITS: false, CAN_SELECT_MULTI_TERMS: true, - SOURCE_FIELDS: [], }; export const SERVERLESS_DEFAULT_VALUES = { SIZE: 10, diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx index febae77ad0f22a..3ff2b70522e9a4 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx @@ -6,7 +6,7 @@ */ import React, { useState, Fragment, useEffect, useCallback } from 'react'; -import { debounce, get } from 'lodash'; +import { get } from 'lodash'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiFieldNumber, @@ -16,7 +16,6 @@ import { EuiSelect, EuiSpacer, } from '@elastic/eui'; -import { getESQLQueryColumns } from '@kbn/esql-utils'; import { getFields, RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { TextBasedLangEditor } from '@kbn/text-based-languages/public'; import { fetchFieldsFromESQL } from '@kbn/text-based-editor'; @@ -24,14 +23,12 @@ import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; import type { AggregateQuery } from '@kbn/es-query'; import { parseDuration } from '@kbn/alerting-plugin/common'; import { - FieldOption, firstFieldOption, getTimeFieldOptions, getTimeOptions, parseAggregationResults, } from '@kbn/triggers-actions-ui-plugin/public/common'; import { DataView } from '@kbn/data-views-plugin/common'; -import { SourceFields } from '../../components/source_fields_select'; import { EsQueryRuleParams, EsQueryRuleMetaData, SearchType } from '../types'; import { DEFAULT_VALUES, SERVERLESS_DEFAULT_VALUES } from '../constants'; import { useTriggerUiActionServices } from '../util'; @@ -42,8 +39,8 @@ import { rowToDocument, toEsQueryHits, transformDatatableToEsqlTable } from '../ export const EsqlQueryExpression: React.FC< RuleTypeParamsExpressionProps, EsQueryRuleMetaData> > = ({ ruleParams, setRuleParams, setRuleProperty, errors }) => { - const { expressions, http, fieldFormats, isServerless, data } = useTriggerUiActionServices(); - const { esqlQuery, timeWindowSize, timeWindowUnit, timeField, sourceFields } = ruleParams; + const { expressions, http, fieldFormats, isServerless } = useTriggerUiActionServices(); + const { esqlQuery, timeWindowSize, timeWindowUnit, timeField } = ruleParams; const [currentRuleParams, setCurrentRuleParams] = useState< EsQueryRuleParams @@ -61,12 +58,12 @@ export const EsqlQueryExpression: React.FC< groupBy: DEFAULT_VALUES.GROUP_BY, termSize: DEFAULT_VALUES.TERM_SIZE, searchType: SearchType.esqlQuery, - sourceFields: sourceFields ?? DEFAULT_VALUES.SOURCE_FIELDS, + // The sourceFields param is ignored for the ES|QL type + sourceFields: [], }); const [query, setQuery] = useState({ esql: '' }); const [timeFieldOptions, setTimeFieldOptions] = useState([firstFieldOption]); const [detectTimestamp, setDetectTimestamp] = useState(false); - const [esFields, setEsFields] = useState([]); const [isLoading, setIsLoading] = useState(false); const setParam = useCallback( @@ -86,7 +83,6 @@ export const EsqlQueryExpression: React.FC< if (esqlQuery) { if (esqlQuery.esql) { refreshTimeFields(esqlQuery); - refreshEsFields(esqlQuery, false); } } if (timeField) { @@ -180,32 +176,6 @@ export const EsqlQueryExpression: React.FC< setDetectTimestamp(hasTimestamp); }; - const refreshEsFields = async (q: AggregateQuery, resetSourceFields: boolean = true) => { - let fields: FieldOption[] = []; - try { - const columns = await getESQLQueryColumns({ - esqlQuery: `${get(q, 'esql')}`, - search: data.search.search, - }); - if (columns.length) { - fields = columns.map((c) => ({ - name: c.id, - type: c.meta.type, - normalizedType: c.meta.type, - searchable: true, - aggregatable: true, - })); - } - } catch (error) { - /** ignore error */ - } - - if (resetSourceFields) { - setParam('sourceFields', undefined); - } - setEsFields(fields); - }; - return ( { + onTextLangQueryChange={(q: AggregateQuery) => { setQuery(q); setParam('esqlQuery', q); refreshTimeFields(q); - refreshEsFields(q); - }, 1000)} + }} expandCodeEditor={() => true} isCodeEditorExpanded={true} onTextLangQuerySubmit={async () => {}} @@ -236,14 +205,6 @@ export const EsqlQueryExpression: React.FC< isLoading={isLoading} /> - - setParam('sourceFields', selectedSourceFields) - } - esFields={esFields} - sourceFields={sourceFields} - errors={errors.sourceFields} - /> = { }, }, shouldWrite: true, + useEcs: true, }; diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.test.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.test.ts index 1d7096d20140eb..b23cddc0eaab7e 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.test.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.test.ts @@ -7,7 +7,7 @@ import { OnlyEsqlQueryRuleParams } from '../types'; import { Comparator } from '../../../../common/comparator_types'; -import { getEsqlQuery } from './fetch_esql_query'; +import { getEsqlQuery, getSourceFields } from './fetch_esql_query'; const getTimeRange = () => { const date = Date.now(); @@ -98,4 +98,30 @@ describe('fetchEsqlQuery', () => { `); }); }); + + describe('getSourceFields', () => { + it('should generate the correct source fields', async () => { + const sourceFields = getSourceFields({ + columns: [ + { name: '@timestamp', type: 'date' }, + { name: 'ecs.version', type: 'keyword' }, + { name: 'error.code', type: 'keyword' }, + ], + values: [['2023-07-12T13:32:04.174Z', '1.8.0', null]], + }); + + expect(sourceFields).toMatchInlineSnapshot(` + Array [ + Object { + "label": "ecs.version", + "searchPath": "ecs.version", + }, + Object { + "label": "error.code", + "searchPath": "error.code", + }, + ] + `); + }); + }); }); diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.ts index 87ae2c1123547f..5ecb258b0579f9 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_esql_query.ts @@ -5,9 +5,11 @@ * 2.0. */ +import { intersectionBy } from 'lodash'; import { parseAggregationResults } from '@kbn/triggers-actions-ui-plugin/common'; import { SharePluginStart } from '@kbn/share-plugin/server'; import { IScopedClusterClient, Logger } from '@kbn/core/server'; +import { ecsFieldMap, alertFieldMap } from '@kbn/alerts-as-data-utils'; import { OnlyEsqlQueryRuleParams } from '../types'; import { EsqlTable, toEsQueryHits } from '../../../../common'; @@ -47,6 +49,8 @@ export async function fetchEsqlQuery({ path: '/_query', body: query, }); + const hits = toEsQueryHits(response); + const sourceFields = getSourceFields(response); const link = `${publicBaseUrl}${spacePrefix}/app/management/insightsAndAlerting/triggersActions/rule/${ruleId}`; @@ -60,10 +64,10 @@ export async function fetchEsqlQuery({ took: 0, timed_out: false, _shards: { failed: 0, successful: 0, total: 0 }, - hits: toEsQueryHits(response), + hits, }, resultLimit: alertLimit, - sourceFieldsParams: params.sourceFields, + sourceFieldsParams: sourceFields, generateSourceFieldsFromHits: true, }), index: null, @@ -98,3 +102,17 @@ export const getEsqlQuery = ( }; return query; }; + +export const getSourceFields = (results: EsqlTable) => { + const resultFields = results.columns.map((c) => ({ + label: c.name, + searchPath: c.name, + })); + const alertFields = Object.keys(alertFieldMap); + const ecsFields = Object.keys(ecsFieldMap) + // exclude the alert fields that we don't want to override + .filter((key) => !alertFields.includes(key)) + .map((key) => ({ label: key, searchPath: key })); + + return intersectionBy(resultFields, ecsFields, 'label'); +}; diff --git a/x-pack/plugins/triggers_actions_ui/common/data/lib/parse_aggregation_results.test.ts b/x-pack/plugins/triggers_actions_ui/common/data/lib/parse_aggregation_results.test.ts index e22d4959c6093b..b881aa76099544 100644 --- a/x-pack/plugins/triggers_actions_ui/common/data/lib/parse_aggregation_results.test.ts +++ b/x-pack/plugins/triggers_actions_ui/common/data/lib/parse_aggregation_results.test.ts @@ -843,9 +843,9 @@ describe('parseAggregationResults', () => { sampleEsqlSourceFieldsHit, ], sourceFields: { - 'host.hostname': ['host-1'], - 'host.id': ['1'], - 'host.name': ['host-1'], + 'host.hostname': ['host-1', 'host-1', 'host-1', 'host-1'], + 'host.id': ['1', '1', '1', '1'], + 'host.name': ['host-1', 'host-1', 'host-1', 'host-1'], }, }, ], diff --git a/x-pack/plugins/triggers_actions_ui/common/data/lib/parse_aggregation_results.ts b/x-pack/plugins/triggers_actions_ui/common/data/lib/parse_aggregation_results.ts index 6fe7040abacc34..756f79dceec979 100644 --- a/x-pack/plugins/triggers_actions_ui/common/data/lib/parse_aggregation_results.ts +++ b/x-pack/plugins/triggers_actions_ui/common/data/lib/parse_aggregation_results.ts @@ -87,10 +87,10 @@ export const parseAggregationResults = ({ sourceFieldsParams.forEach((field) => { if (generateSourceFieldsFromHits) { - const fieldsSet = new Set(); + const fieldsSet: string[] = []; groupBucket.topHitsAgg.hits.hits.forEach((hit: SearchHit<{ [key: string]: string }>) => { if (hit._source && hit._source[field.label]) { - fieldsSet.add(hit._source[field.label]); + fieldsSet.push(hit._source[field.label]); } }); sourceFields[field.label] = Array.from(fieldsSet); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/builtin_alert_types/es_query/esql_only.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/builtin_alert_types/es_query/esql_only.ts index f193af1b81703c..56934c5d5f8a39 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/builtin_alert_types/es_query/esql_only.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/builtin_alert_types/es_query/esql_only.ts @@ -22,7 +22,6 @@ import { RULE_INTERVAL_MILLIS, RULE_INTERVAL_SECONDS, RULE_TYPE_ID, - SourceField, } from './common'; import { createDataStream, deleteDataStream } from '../../../create_test_data'; @@ -39,12 +38,6 @@ export default function ruleTests({ getService }: FtrProviderContext) { getAllAADDocs, } = getRuleServices(getService); - const sourceFields = [ - { label: 'host.hostname', searchPath: 'host.hostname.keyword' }, - { label: 'host.id', searchPath: 'host.id' }, - { label: 'host.name', searchPath: 'host.name' }, - ]; - describe('rule', async () => { let endDate: string; let connectorId: string; @@ -81,13 +74,11 @@ export default function ruleTests({ getService }: FtrProviderContext) { name: 'never fire', esqlQuery: 'from .kibana-alerting-test-data | stats c = count(date) by host.hostname, host.name, host.id | where c < 0', - sourceFields, }); await createRule({ name: 'always fire', esqlQuery: 'from .kibana-alerting-test-data | stats c = count(date) by host.hostname, host.name, host.id | where c > -1', - sourceFields, }); const docs = await waitForDocs(2); @@ -225,13 +216,11 @@ export default function ruleTests({ getService }: FtrProviderContext) { name: 'never fire', esqlQuery: 'from test-data-stream | stats c = count(@timestamp) by host.hostname, host.name, host.id | where c < 0', - sourceFields, }); await createRule({ name: 'always fire', esqlQuery: 'from test-data-stream | stats c = count(@timestamp) by host.hostname, host.name, host.id | where c > -1', - sourceFields, }); const messagePattern = /Document count is \d+ in the last 20s. Alert when greater than 0./; @@ -397,7 +386,6 @@ export default function ruleTests({ getService }: FtrProviderContext) { groupBy?: string; termField?: string; termSize?: number; - sourceFields?: SourceField[]; } async function createRule(params: CreateRuleParams): Promise { @@ -469,7 +457,7 @@ export default function ruleTests({ getService }: FtrProviderContext) { termSize: params.termSize, timeField: params.timeField || 'date', esqlQuery: { esql: params.esqlQuery }, - sourceFields: params.sourceFields, + sourceFields: [], }, }) .expect(200); diff --git a/x-pack/test/api_integration/apis/maps/maps_telemetry.ts b/x-pack/test/api_integration/apis/maps/maps_telemetry.ts index 8f5c9ae95f8af9..acd846f77c9826 100644 --- a/x-pack/test/api_integration/apis/maps/maps_telemetry.ts +++ b/x-pack/test/api_integration/apis/maps/maps_telemetry.ts @@ -36,8 +36,8 @@ export default function ({ getService }: FtrProviderContext) { return fieldStat.name === 'geo_point'; } ); - expect(geoPointFieldStats.count).to.be(39); - expect(geoPointFieldStats.index_count).to.be(10); + expect(geoPointFieldStats.count).to.be(47); + expect(geoPointFieldStats.index_count).to.be(11); const geoShapeFieldStats = apiResponse.cluster_stats.indices.mappings.field_types.find( (fieldStat: estypes.ClusterStatsFieldTypes) => { From b810572ca0d744e3d024bf20598467f24c398201 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 18 Jun 2024 15:53:43 +0100 Subject: [PATCH 035/123] [ML] Refresh jobs list after import (#184757) Fixes https://github.com/elastic/kibana/issues/184063 Adds a callback prop to allow the import flyout to refresh the jobs list after importing jobs or synchronising saved objects. --- .../import_jobs_flyout/import_jobs_flyout.tsx | 6 +++++- .../components/jobs_list_page/jobs_list_page.tsx | 13 +++++++++++-- .../space_management/space_management.tsx | 14 +++++++++++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/ml/public/application/components/import_export_jobs/import_jobs_flyout/import_jobs_flyout.tsx b/x-pack/plugins/ml/public/application/components/import_export_jobs/import_jobs_flyout/import_jobs_flyout.tsx index e98881f1e56d8b..d0870466aa89ac 100644 --- a/x-pack/plugins/ml/public/application/components/import_export_jobs/import_jobs_flyout/import_jobs_flyout.tsx +++ b/x-pack/plugins/ml/public/application/components/import_export_jobs/import_jobs_flyout/import_jobs_flyout.tsx @@ -45,9 +45,10 @@ import { useEnabledFeatures } from '../../../contexts/ml'; export interface Props { isDisabled: boolean; + onImportComplete: (() => void) | null; } -export const ImportJobsFlyout: FC = ({ isDisabled }) => { +export const ImportJobsFlyout: FC = ({ isDisabled, onImportComplete }) => { const { services: { data: { @@ -204,6 +205,9 @@ export const ImportJobsFlyout: FC = ({ isDisabled }) => { setImporting(false); setShowFlyout(false); + if (typeof onImportComplete === 'function') { + onImportComplete(); + } // eslint-disable-next-line react-hooks/exhaustive-deps }, [jobType, jobIdObjects, adJobs, dfaJobs]); diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx index 39b9520876fb02..ca0617bedc1c71 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx +++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx @@ -74,6 +74,8 @@ export const JobsListPage: FC = ({ const [isPlatinumOrTrialLicense, setIsPlatinumOrTrialLicense] = useState(true); const [showSyncFlyout, setShowSyncFlyout] = useState(false); const [currentTabId, setCurrentTabId] = useState('anomaly-detector'); + // callback to allow import flyout to refresh jobs list + const [refreshJobs, setRefreshJobs] = useState<(() => void) | null>(null); const mlServices = useMemo( () => getMlGlobalServices(coreStart.http, data.dataViews, usageCollection), @@ -109,6 +111,9 @@ export const JobsListPage: FC = ({ } function onCloseSyncFlyout() { + if (typeof refreshJobs === 'function') { + refreshJobs(); + } setShowSyncFlyout(false); } @@ -203,10 +208,14 @@ export const JobsListPage: FC = ({ /> - + - + diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/space_management/space_management.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/space_management/space_management.tsx index fd65469f884d55..76c3293f97061c 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/space_management/space_management.tsx +++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/space_management/space_management.tsx @@ -34,10 +34,11 @@ import { getFilters } from './filters'; interface Props { spacesApi?: SpacesPluginStart; - setCurrentTab: (tabId: MlSavedObjectType) => void; + onTabChange: (tabId: MlSavedObjectType) => void; + onReload: React.Dispatch void) | null>>; } -export const SpaceManagement: FC = ({ spacesApi, setCurrentTab }) => { +export const SpaceManagement: FC = ({ spacesApi, onTabChange, onReload }) => { const { getList } = useManagementApiService(); const [currentTabId, setCurrentTabId] = useState(null); @@ -101,12 +102,19 @@ export const SpaceManagement: FC = ({ spacesApi, setCurrentTab }) => { [getList, loadingTab] ); + useEffect(() => { + onReload(() => () => refresh(currentTabId)); + return () => { + onReload(null); + }; + }, [currentTabId, refresh, onReload]); + useEffect( function refreshOnTabChange() { setItems(undefined); if (currentTabId !== null) { setColumns(createColumns()); - setCurrentTab(currentTabId); + onTabChange(currentTabId); refresh(currentTabId); setPageIndex(0); } From bee8973c51955944026c3be9513410b7e0cb282c Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 18 Jun 2024 08:07:48 -0700 Subject: [PATCH 036/123] [DOCS] Deprecate old advanced settings (#186309) --- docs/management/advanced-options.asciidoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index bad18a706cbf29..98886aedd5535a 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -310,6 +310,7 @@ Limits the number of rows per page in the document table. Sets the maximum number of rows for the entire document table. This is the maximum number of documents fetched from {es}. [[discover-searchFieldsFromSource]]`discover:searchFieldsFromSource`:: +deprecated:[8.15.0] Load fields from the original JSON {ref}/mapping-source-field.html[`_source`]. When disabled, *Discover* loads fields using the {es} search API's {ref}/search-fields.html#search-fields-param[`fields`] parameter. @@ -339,7 +340,7 @@ Highlights results in *Discover* and saved searches on dashboards. Highlighting slows requests when working on big documents. [[doctable-legacy]]`doc_table:legacy`:: -Controls the way the document table looks and works. +deprecated:[8.15.0] Controls the way the document table looks and works. To use the new *Document Explorer* instead of the classic view, turn off this option. The *Document Explorer* offers better data sorting, resizable columns, and a full screen view. @@ -512,7 +513,7 @@ deprecated::[8.11.0,'Rollups are deprecated and will be removed in a future vers [horizontal] [[rollups-enableindexpatterns]]`rollups:enableIndexPatterns`:: -Enables the creation of data views that capture rollup indices, which in +deprecated:[8.15.0] Enables the creation of data views that capture rollup indices, which in turn enables visualizations based on rollup data. Refresh the page to apply the changes. From 67933dcb470049ea89998718ea450df85828e876 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 18 Jun 2024 17:43:04 +0200 Subject: [PATCH 037/123] [OAS] Deprecations (#186062) ## Summary Adds support for the [`deprecated` field](https://swagger.io/specification/) at the operation level to our router conversion logic. Close https://github.com/elastic/kibana/issues/186003 --- .../src/router.test.ts | 15 ++++++++++++++- .../core_versioned_router.test.ts | 12 ++++++++++-- .../http/core-http-server/src/router/route.ts | 8 ++++++++ .../http/core-http-server/src/versioning/types.ts | 10 +++++++++- .../src/__snapshots__/generate_oas.test.ts.snap | 6 +----- .../src/generate_oas.test.util.ts | 1 + .../src/process_router.ts | 3 ++- .../src/process_versioned_router.ts | 3 ++- 8 files changed, 47 insertions(+), 11 deletions(-) diff --git a/packages/core/http/core-http-router-server-internal/src/router.test.ts b/packages/core/http/core-http-router-server-internal/src/router.test.ts index cab011a5f0f720..c9d9c28a888236 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.test.ts @@ -43,7 +43,15 @@ describe('Router', () => { const router = new Router('', logger, enhanceWithContext, routerOptions); const validation = schema.object({ foo: schema.string() }); router.post( - { path: '/', validate: { body: validation, query: validation, params: validation } }, + { + path: '/', + validate: { body: validation, query: validation, params: validation }, + options: { + deprecated: true, + summary: 'post test summary', + description: 'post test description', + }, + }, (context, req, res) => res.ok() ); const routes = router.getRoutes(); @@ -55,6 +63,11 @@ describe('Router', () => { path: '/', validationSchemas: { body: validation, query: validation, params: validation }, isVersioned: false, + options: { + deprecated: true, + summary: 'post test summary', + description: 'post test description', + }, }); }); diff --git a/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.test.ts b/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.test.ts index 8b5a7d23fa0eea..c29a3edd967af2 100644 --- a/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.test.ts @@ -32,8 +32,13 @@ describe('Versioned router', () => { it('provides the expected metadata', () => { const versionedRouter = CoreVersionedRouter.from({ router }); - versionedRouter.get({ path: '/test/{id}', access: 'internal' }); - versionedRouter.post({ path: '/test', access: 'internal' }); + versionedRouter.get({ path: '/test/{id}', access: 'internal', deprecated: true }); + versionedRouter.post({ + path: '/test', + access: 'internal', + summary: 'Post test', + description: 'Post test description', + }); versionedRouter.delete({ path: '/test', access: 'internal' }); expect(versionedRouter.getRoutes()).toMatchInlineSnapshot(` Array [ @@ -42,6 +47,7 @@ describe('Versioned router', () => { "method": "get", "options": Object { "access": "internal", + "deprecated": true, }, "path": "/test/{id}", }, @@ -50,6 +56,8 @@ describe('Versioned router', () => { "method": "post", "options": Object { "access": "internal", + "description": "Post test description", + "summary": "Post test", }, "path": "/test", }, diff --git a/packages/core/http/core-http-server/src/router/route.ts b/packages/core/http/core-http-server/src/router/route.ts index 983c495a1b5414..aa5b8598e0d0b4 100644 --- a/packages/core/http/core-http-server/src/router/route.ts +++ b/packages/core/http/core-http-server/src/router/route.ts @@ -198,6 +198,14 @@ export interface RouteConfigOptions { * ``` */ description?: string; + + /** + * Setting this to `true` declares this route to be deprecated. Consumers SHOULD + * refrain from usage of this route. + * + * @remarks This will be surfaced in OAS documentation. + */ + deprecated?: boolean; } /** diff --git a/packages/core/http/core-http-server/src/versioning/types.ts b/packages/core/http/core-http-server/src/versioning/types.ts index af3173691415f9..5c4eb459196cc2 100644 --- a/packages/core/http/core-http-server/src/versioning/types.ts +++ b/packages/core/http/core-http-server/src/versioning/types.ts @@ -32,7 +32,7 @@ export type VersionedRouteConfig = Omit< RouteConfig, 'validate' | 'options' > & { - options?: Omit, 'access' | 'description'>; + options?: Omit, 'access' | 'description' | 'deprecated'>; /** See {@link RouteConfigOptions['access']} */ access: Exclude['access'], undefined>; /** @@ -82,6 +82,14 @@ export type VersionedRouteConfig = Omit< * ``` */ description?: string; + + /** + * Declares this operation to be deprecated. Consumers SHOULD refrain from usage + * of this route. This will be surfaced in OAS documentation. + * + * @default false + */ + deprecated?: boolean; }; /** diff --git a/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap b/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap index fee1a8534a7ec7..be1b698f5cd9a6 100644 --- a/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap +++ b/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap @@ -26,7 +26,6 @@ Object { "paths": Object { "/foo/{id}": Object { "get": Object { - "description": undefined, "operationId": "/foo/{id}#0", "parameters": Array [ Object { @@ -133,7 +132,7 @@ Object { "paths": Object { "/bar": Object { "get": Object { - "description": undefined, + "deprecated": true, "operationId": "/bar#0", "parameters": Array [ Object { @@ -577,7 +576,6 @@ Object { "paths": Object { "/recursive": Object { "get": Object { - "description": undefined, "operationId": "/recursive#0", "parameters": Array [ Object { @@ -660,7 +658,6 @@ Object { "paths": Object { "/foo/{id}": Object { "get": Object { - "description": undefined, "operationId": "/foo/{id}#0", "parameters": Array [ Object { @@ -698,7 +695,6 @@ Object { }, "/test": Object { "get": Object { - "description": undefined, "operationId": "/test#0", "parameters": Array [ Object { diff --git a/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts b/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts index bed7d10c51d8e4..2fb821018dcee6 100644 --- a/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts +++ b/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts @@ -85,6 +85,7 @@ export const getVersionedRouterDefaults = () => ({ options: { summary: 'versioned route', access: 'public', + deprecated: true, options: { tags: ['ignore-me', 'oas-tag:versioned'], }, diff --git a/packages/kbn-router-to-openapispec/src/process_router.ts b/packages/kbn-router-to-openapispec/src/process_router.ts index 393b745b6aab31..9437612211a920 100644 --- a/packages/kbn-router-to-openapispec/src/process_router.ts +++ b/packages/kbn-router-to-openapispec/src/process_router.ts @@ -61,8 +61,9 @@ export const processRouter = ( const operation: OpenAPIV3.OperationObject = { summary: route.options.summary ?? '', - description: route.options.description, tags: route.options.tags ? extractTags(route.options.tags) : [], + ...(route.options.description ? { description: route.options.description } : {}), + ...(route.options.deprecated ? { deprecated: route.options.deprecated } : {}), requestBody: !!validationSchemas?.body ? { content: { diff --git a/packages/kbn-router-to-openapispec/src/process_versioned_router.ts b/packages/kbn-router-to-openapispec/src/process_versioned_router.ts index cc873b26835cf3..19b41f4812a30c 100644 --- a/packages/kbn-router-to-openapispec/src/process_versioned_router.ts +++ b/packages/kbn-router-to-openapispec/src/process_versioned_router.ts @@ -85,8 +85,9 @@ export const processVersionedRouter = ( const hasVersionFilter = Boolean(filters?.version); const operation: OpenAPIV3.OperationObject = { summary: route.options.summary ?? '', - description: route.options.description, tags: route.options.options?.tags ? extractTags(route.options.options.tags) : [], + ...(route.options.description ? { description: route.options.description } : {}), + ...(route.options.deprecated ? { deprecated: route.options.deprecated } : {}), requestBody: hasBody ? { content: hasVersionFilter From 8641aeea2d3b5c53686a99c2f79fc85ea7676a64 Mon Sep 17 00:00:00 2001 From: Joe McElroy Date: Tue, 18 Jun 2024 16:44:00 +0100 Subject: [PATCH 038/123] [Search] [Playground] Semantic text support (#186268) ## Summary This adds semantic_text support to Chat playground. - We detect the presence of semantic_text and favour these fields over any other ones. - We do a nested query if the field is a semantic_text type, and use the inner_hits to populate the context - This was manually tested through the QA scenarios list and I added a couple more scenarios for semantic_text. - Added to telemetry key with `_SEMANTIC` entry Coverage is still units but this change is pretty well covered. FTRs will follow once we have basic "full chat" flow. ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../fetch_query_source_fields.mock.ts | 172 +++++- .../plugins/search_playground/common/types.ts | 15 +- .../edit_context/edit_context_flyout.test.tsx | 2 + .../view_query/view_query_flyout.test.tsx | 9 +- .../view_query/view_query_flyout.tsx | 12 +- .../public/hooks/use_source_indices_field.ts | 2 +- .../hooks/use_source_indices_fields.test.tsx | 23 +- .../public/utils/create_query.test.ts | 502 ++++++++++++------ .../public/utils/create_query.ts | 101 +++- .../server/lib/conversational_chain.test.ts | 51 ++ .../server/lib/elasticsearch_retriever.ts | 2 +- .../lib/fetch_query_source_fields.test.ts | 163 +++++- .../server/lib/fetch_query_source_fields.ts | 101 +++- .../get_value_for_selected_field.test.ts | 54 +- .../utils/get_value_for_selected_field.ts | 16 +- 15 files changed, 993 insertions(+), 232 deletions(-) diff --git a/x-pack/plugins/search_playground/__mocks__/fetch_query_source_fields.mock.ts b/x-pack/plugins/search_playground/__mocks__/fetch_query_source_fields.mock.ts index b25ca903c7a4b8..d421ad6c8c9b75 100644 --- a/x-pack/plugins/search_playground/__mocks__/fetch_query_source_fields.mock.ts +++ b/x-pack/plugins/search_playground/__mocks__/fetch_query_source_fields.mock.ts @@ -5,7 +5,177 @@ * 2.0. */ -import { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; +import { IndicesGetMappingResponse, SearchResponse } from '@elastic/elasticsearch/lib/api/types'; + +export const SPARSE_SEMANTIC_FIELD_FIELD_CAPS = { + indices: ['test-index2'], + fields: { + infer_field: { + semantic_text: { + type: 'semantic_text', + metadata_field: false, + searchable: false, + aggregatable: false, + }, + }, + 'infer_field.inference.chunks.embeddings': { + sparse_vector: { + type: 'sparse_vector', + metadata_field: false, + searchable: true, + aggregatable: false, + }, + }, + non_infer_field: { + text: { + type: 'text', + metadata_field: false, + searchable: true, + aggregatable: false, + }, + }, + 'infer_field.inference.chunks.text': { + keyword: { + type: 'keyword', + metadata_field: false, + searchable: false, + aggregatable: false, + }, + }, + 'infer_field.inference': { + object: { + type: 'object', + metadata_field: false, + searchable: false, + aggregatable: false, + }, + }, + 'infer_field.inference.chunks': { + nested: { + type: 'nested', + metadata_field: false, + searchable: false, + aggregatable: false, + }, + }, + }, +}; + +export const SPARSE_SEMANTIC_FIELD_MAPPINGS = { + 'test-index2': { + mappings: { + properties: { + infer_field: { + type: 'semantic_text', + inference_id: 'elser-endpoint', + model_settings: { + task_type: 'sparse_embedding', + }, + }, + non_infer_field: { + type: 'text', + }, + }, + }, + }, +} as any as IndicesGetMappingResponse; + +export const DENSE_SEMANTIC_FIELD_MAPPINGS = { + 'test-index2': { + mappings: { + properties: { + infer_field: { + type: 'semantic_text', + inference_id: 'cohere', + model_settings: { + task_type: 'text_embedding', + dimensions: 1536, + similarity: 'dot_product', + }, + }, + non_infer_field: { + type: 'text', + }, + }, + }, + }, +} as any as IndicesGetMappingResponse; + +// for when semantic_text field hasn't been mapped with task_type +// when theres no data / no inference has been performed in the field +export const DENSE_SEMANTIC_FIELD_MAPPINGS_MISSING_TASK_TYPE = { + 'test-index2': { + mappings: { + properties: { + infer_field: { + type: 'semantic_text', + inference_id: 'cohere', + model_settings: { + dimensions: 1536, + similarity: 'dot_product', + }, + }, + non_infer_field: { + type: 'text', + }, + }, + }, + }, +} as any as IndicesGetMappingResponse; + +export const DENSE_SEMANTIC_FIELD_FIELD_CAPS = { + indices: ['test-index2'], + fields: { + infer_field: { + semantic_text: { + type: 'semantic_text', + metadata_field: false, + searchable: false, + aggregatable: false, + }, + }, + 'infer_field.inference.chunks.embeddings': { + sparse_vector: { + type: 'dense_vector', + metadata_field: false, + searchable: true, + aggregatable: false, + }, + }, + non_infer_field: { + text: { + type: 'text', + metadata_field: false, + searchable: true, + aggregatable: false, + }, + }, + 'infer_field.inference.chunks.text': { + keyword: { + type: 'keyword', + metadata_field: false, + searchable: false, + aggregatable: false, + }, + }, + 'infer_field.inference': { + object: { + type: 'object', + metadata_field: false, + searchable: false, + aggregatable: false, + }, + }, + 'infer_field.inference.chunks': { + nested: { + type: 'nested', + metadata_field: false, + searchable: false, + aggregatable: false, + }, + }, + }, +}; export const DENSE_SPARSE_SAME_FIELD_NAME_CAPS = { indices: ['cohere-embeddings', 'elser_index'], diff --git a/x-pack/plugins/search_playground/common/types.ts b/x-pack/plugins/search_playground/common/types.ts index c788b2df1896fb..00bfde68ec2eab 100644 --- a/x-pack/plugins/search_playground/common/types.ts +++ b/x-pack/plugins/search_playground/common/types.ts @@ -7,18 +7,25 @@ export type IndicesQuerySourceFields = Record; -interface ModelFields { +interface ModelField { field: string; model_id: string; - nested: boolean; + indices: string[]; +} + +interface SemanticField { + field: string; + inferenceId: string; + embeddingType: 'sparse_vector' | 'dense_vector'; indices: string[]; } export interface QuerySourceFields { - elser_query_fields: ModelFields[]; - dense_vector_query_fields: ModelFields[]; + elser_query_fields: ModelField[]; + dense_vector_query_fields: ModelField[]; bm25_query_fields: string[]; source_fields: string[]; + semantic_fields: SemanticField[]; skipped_fields: number; } diff --git a/x-pack/plugins/search_playground/public/components/edit_context/edit_context_flyout.test.tsx b/x-pack/plugins/search_playground/public/components/edit_context/edit_context_flyout.test.tsx index 4e5bb7f807900f..de82892b167be1 100644 --- a/x-pack/plugins/search_playground/public/components/edit_context/edit_context_flyout.test.tsx +++ b/x-pack/plugins/search_playground/public/components/edit_context/edit_context_flyout.test.tsx @@ -19,12 +19,14 @@ jest.mock('../../hooks/use_indices_fields', () => ({ dense_vector_query_fields: [], bm25_query_fields: ['field1', 'field2'], source_fields: ['context_field1', 'context_field2'], + semantic_fields: [], }, index2: { elser_query_fields: [], dense_vector_query_fields: [], bm25_query_fields: ['field1', 'field2'], source_fields: ['context_field1', 'context_field2'], + semantic_fields: [], }, }, }), diff --git a/x-pack/plugins/search_playground/public/components/view_query/view_query_flyout.test.tsx b/x-pack/plugins/search_playground/public/components/view_query/view_query_flyout.test.tsx index 410989eaf52ad4..39136e25572960 100644 --- a/x-pack/plugins/search_playground/public/components/view_query/view_query_flyout.test.tsx +++ b/x-pack/plugins/search_playground/public/components/view_query/view_query_flyout.test.tsx @@ -10,6 +10,7 @@ import { render, fireEvent, screen } from '@testing-library/react'; import { ViewQueryFlyout } from './view_query_flyout'; import { FormProvider, useForm } from 'react-hook-form'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import { ChatFormFields } from '../../types'; jest.mock('../../hooks/use_indices_fields', () => ({ useIndicesFields: () => ({ @@ -19,12 +20,14 @@ jest.mock('../../hooks/use_indices_fields', () => ({ dense_vector_query_fields: [], bm25_query_fields: ['field1', 'field2'], skipped_fields: 1, + semantic_fields: [], }, index2: { elser_query_fields: [], dense_vector_query_fields: [], bm25_query_fields: ['field1', 'field2'], skipped_fields: 0, + semantic_fields: [], }, }, }), @@ -41,7 +44,11 @@ jest.mock('../../hooks/use_usage_tracker', () => ({ const MockFormProvider = ({ children }: { children: React.ReactElement }) => { const methods = useForm({ values: { - indices: ['index1', 'index2'], + [ChatFormFields.indices]: ['index1', 'index2'], + [ChatFormFields.sourceFields]: { + index1: ['field1'], + index2: ['field1'], + }, }, }); return {children}; diff --git a/x-pack/plugins/search_playground/public/components/view_query/view_query_flyout.tsx b/x-pack/plugins/search_playground/public/components/view_query/view_query_flyout.tsx index 64139307de4bab..2fd64f073eac74 100644 --- a/x-pack/plugins/search_playground/public/components/view_query/view_query_flyout.tsx +++ b/x-pack/plugins/search_playground/public/components/view_query/view_query_flyout.tsx @@ -65,6 +65,12 @@ const groupTypeQueryFields = ( typeQueryFields += (typeQueryFields ? '_' : '') + 'SPARSE'; } + if ( + selectedFields.some((field) => indexFields.semantic_fields.find((f) => f.field === field)) + ) { + typeQueryFields += (typeQueryFields ? '_' : '') + 'SEMANTIC'; + } + return typeQueryFields; }); @@ -76,6 +82,7 @@ export const ViewQueryFlyout: React.FC = ({ onClose }) => const usageTracker = useUsageTracker(); const { getValues } = useFormContext(); const selectedIndices: string[] = getValues(ChatFormFields.indices); + const sourceFields = getValues(ChatFormFields.sourceFields); const { fields } = useIndicesFields(selectedIndices); const defaultFields = getDefaultQueryFields(fields); @@ -111,7 +118,7 @@ export const ViewQueryFlyout: React.FC = ({ onClose }) => const saveQuery = () => { queryFieldsOnChange(tempQueryFields); - elasticsearchQueryChange(createQuery(tempQueryFields, fields)); + elasticsearchQueryChange(createQuery(tempQueryFields, sourceFields, fields)); onClose(); const groupedQueryFields = groupTypeQueryFields(fields, tempQueryFields); @@ -168,7 +175,7 @@ export const ViewQueryFlyout: React.FC = ({ onClose }) => lineNumbers data-test-subj="ViewElasticsearchQueryResult" > - {JSON.stringify(createQuery(tempQueryFields, fields), null, 2)} + {JSON.stringify(createQuery(tempQueryFields, sourceFields, fields), null, 2)} @@ -198,6 +205,7 @@ export const ViewQueryFlyout: React.FC = ({ onClose }) => aria-label="Select query fields" data-test-subj={`queryFieldsSelectable_${index}`} options={[ + ...group.semantic_fields, ...group.elser_query_fields, ...group.dense_vector_query_fields, ...group.bm25_query_fields, diff --git a/x-pack/plugins/search_playground/public/hooks/use_source_indices_field.ts b/x-pack/plugins/search_playground/public/hooks/use_source_indices_field.ts index 342be7c1917782..bc9a37060fb6f8 100644 --- a/x-pack/plugins/search_playground/public/hooks/use_source_indices_field.ts +++ b/x-pack/plugins/search_playground/public/hooks/use_source_indices_field.ts @@ -89,7 +89,7 @@ export const useSourceIndicesFields = () => { setNoFieldsIndicesWarning(null); } - onElasticsearchQueryChange(createQuery(defaultFields, fields)); + onElasticsearchQueryChange(createQuery(defaultFields, defaultSourceFields, fields)); onSourceFieldsChange(defaultSourceFields); usageTracker?.count( AnalyticsEvents.sourceFieldsLoaded, diff --git a/x-pack/plugins/search_playground/public/hooks/use_source_indices_fields.test.tsx b/x-pack/plugins/search_playground/public/hooks/use_source_indices_fields.test.tsx index f3b19e8d4360ec..7dd1a43d6fc01f 100644 --- a/x-pack/plugins/search_playground/public/hooks/use_source_indices_fields.test.tsx +++ b/x-pack/plugins/search_playground/public/hooks/use_source_indices_fields.test.tsx @@ -36,7 +36,6 @@ describe.skip('useSourceIndicesFields Hook', () => { { field: 'field1', model_id: 'model1', - nested: false, indices: ['newIndex'], }, ], @@ -44,6 +43,7 @@ describe.skip('useSourceIndicesFields Hook', () => { bm25_query_fields: [], source_fields: ['field1'], skipped_fields: 0, + semantic_fields: [], }, }; @@ -87,11 +87,11 @@ describe.skip('useSourceIndicesFields Hook', () => { expect(result.current.indices).toEqual([]); expect(getValues()).toMatchInlineSnapshot(` Object { - "doc_size": 5, + "doc_size": 3, "elasticsearch_query": Object {}, "indices": Array [], "prompt": "You are an assistant for question-answering tasks.", - "source_fields": Array [], + "source_fields": Object {}, } `); result.current.addIndex('newIndex'); @@ -109,16 +109,15 @@ describe.skip('useSourceIndicesFields Hook', () => { expect(result.current.loading).toBe(false); expect(getValues()).toMatchInlineSnapshot(` Object { - "doc_size": 5, + "doc_size": 3, "elasticsearch_query": Object { "retriever": Object { "standard": Object { "query": Object { - "text_expansion": Object { - "field1": Object { - "model_id": "model1", - "model_text": "{query}", - }, + "sparse_vector": Object { + "field": "field1", + "inference_id": "model1", + "query": "{query}", }, }, }, @@ -146,6 +145,7 @@ describe.skip('useSourceIndicesFields Hook', () => { bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; @@ -169,7 +169,7 @@ describe.skip('useSourceIndicesFields Hook', () => { expect(result.current.loading).toBe(false); expect(getValues()).toMatchInlineSnapshot(` Object { - "doc_size": 5, + "doc_size": 3, "elasticsearch_query": Object { "retriever": Object { "standard": Object { @@ -199,6 +199,7 @@ describe.skip('useSourceIndicesFields Hook', () => { bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; @@ -222,7 +223,7 @@ describe.skip('useSourceIndicesFields Hook', () => { expect(result.current.loading).toBe(false); expect(getValues()).toMatchInlineSnapshot(` Object { - "doc_size": 5, + "doc_size": 3, "elasticsearch_query": Object { "retriever": Object { "standard": Object { diff --git a/x-pack/plugins/search_playground/public/utils/create_query.test.ts b/x-pack/plugins/search_playground/public/utils/create_query.test.ts index 282326f0991d2b..164f79618d74cb 100644 --- a/x-pack/plugins/search_playground/public/utils/create_query.test.ts +++ b/x-pack/plugins/search_playground/public/utils/create_query.test.ts @@ -9,6 +9,8 @@ import { IndicesQuerySourceFields } from '../types'; import { createQuery, getDefaultQueryFields, getDefaultSourceFields } from './create_query'; describe('create_query', () => { + const sourceFields = { index1: [], index2: [] }; + describe('createQuery', () => { it('should return a sparse single query', () => { const fields = { @@ -17,25 +19,23 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { - elser_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + elser_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; - expect(createQuery(fields, fieldDescriptors)).toEqual({ + expect(createQuery(fields, sourceFields, fieldDescriptors)).toEqual({ retriever: { standard: { query: { - text_expansion: { - field1: { - model_id: 'model1', - model_text: '{query}', - }, + sparse_vector: { + field: 'field1', + inference_id: 'model1', + query: '{query}', }, }, }, @@ -51,16 +51,15 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { elser_query_fields: [], - dense_vector_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + dense_vector_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; - expect(createQuery(fields, fieldDescriptors)).toEqual({ + expect(createQuery(fields, sourceFields, fieldDescriptors)).toEqual({ retriever: { standard: { query: { @@ -89,33 +88,34 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { elser_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1', 'index2'] }, + { field: 'field1', model_id: 'model1', indices: ['index1', 'index2'] }, ], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, index2: { elser_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1', 'index2'] }, + { field: 'field1', model_id: 'model1', indices: ['index1', 'index2'] }, ], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; - expect(createQuery(fields, fieldDescriptors)).toEqual({ + expect(createQuery(fields, sourceFields, fieldDescriptors)).toEqual({ retriever: { standard: { query: { - text_expansion: { - field1: { - model_id: 'model1', - model_text: '{query}', - }, + sparse_vector: { + field: 'field1', + inference_id: 'model1', + query: '{query}', }, }, }, @@ -131,37 +131,34 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { - elser_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + elser_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, index2: { - elser_query_fields: [ - { field: 'field2', model_id: 'model1', nested: false, indices: ['index2'] }, - ], + elser_query_fields: [{ field: 'field2', model_id: 'model1', indices: ['index2'] }], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; - expect(createQuery(fields, fieldDescriptors)).toEqual({ + expect(createQuery(fields, sourceFields, fieldDescriptors)).toEqual({ retriever: { rrf: { retrievers: [ { standard: { query: { - text_expansion: { - field1: { - model_id: 'model1', - model_text: '{query}', - }, + sparse_vector: { + field: 'field1', + inference_id: 'model1', + query: '{query}', }, }, }, @@ -169,11 +166,10 @@ describe('create_query', () => { { standard: { query: { - text_expansion: { - field2: { - model_id: 'model1', - model_text: '{query}', - }, + sparse_vector: { + field: 'field2', + inference_id: 'model1', + query: '{query}', }, }, }, @@ -184,72 +180,6 @@ describe('create_query', () => { }); }); - it('should return empty for nested dense query', () => { - const fields = { - index1: ['passages.field1.predicted_value'], - }; - - const fieldDescriptors: IndicesQuerySourceFields = { - index1: { - elser_query_fields: [], - dense_vector_query_fields: [ - { - field: 'passages.field1.predicted_value', - model_id: 'model1', - nested: true, - indices: ['index1'], - }, - ], - bm25_query_fields: [], - source_fields: [], - skipped_fields: 0, - }, - }; - - expect(createQuery(fields, fieldDescriptors)).toEqual({ - retriever: { - standard: { - query: { - match_all: {}, - }, - }, - }, - }); - }); - - it('should return empty for nested sparse query', () => { - const fields = { - index1: ['passages.field1.tokens'], - }; - - const fieldDescriptors: IndicesQuerySourceFields = { - index1: { - elser_query_fields: [ - { - field: 'passages.field1.tokens', - model_id: 'model1', - nested: true, - indices: ['index1'], - }, - ], - dense_vector_query_fields: [], - bm25_query_fields: [], - source_fields: [], - skipped_fields: 0, - }, - }; - - expect(createQuery(fields, fieldDescriptors)).toEqual({ - retriever: { - standard: { - query: { - match_all: {}, - }, - }, - }, - }); - }); - describe('hybrid without RRF', () => { it('should return a hybrid query', () => { const fields = { @@ -259,37 +189,34 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { - elser_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + elser_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], dense_vector_query_fields: [], bm25_query_fields: ['content', 'title'], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, index2: { - elser_query_fields: [ - { field: 'field2', model_id: 'model1', nested: false, indices: ['index2'] }, - ], + elser_query_fields: [{ field: 'field2', model_id: 'model1', indices: ['index2'] }], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; - expect(createQuery(fields, fieldDescriptors, { rrf: false })).toEqual({ + expect(createQuery(fields, sourceFields, fieldDescriptors, { rrf: false })).toEqual({ retriever: { standard: { query: { bool: { should: [ { - text_expansion: { - field1: { - model_id: 'model1', - model_text: '{query}', - }, + sparse_vector: { + field: 'field1', + inference_id: 'model1', + query: '{query}', }, }, { @@ -299,11 +226,10 @@ describe('create_query', () => { }, }, { - text_expansion: { - field2: { - model_id: 'model1', - model_text: '{query}', - }, + sparse_vector: { + field: 'field2', + inference_id: 'model1', + query: '{query}', }, }, ], @@ -325,37 +251,34 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { - elser_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + elser_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], dense_vector_query_fields: [], bm25_query_fields: ['content', 'title'], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, index2: { - elser_query_fields: [ - { field: 'field2', model_id: 'model1', nested: false, indices: ['index2'] }, - ], + elser_query_fields: [{ field: 'field2', model_id: 'model1', indices: ['index2'] }], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; - expect(createQuery(fields, fieldDescriptors)).toEqual({ + expect(createQuery(fields, sourceFields, fieldDescriptors)).toEqual({ retriever: { rrf: { retrievers: [ { standard: { query: { - text_expansion: { - field1: { - model_id: 'model1', - model_text: '{query}', - }, + sparse_vector: { + field: 'field1', + inference_id: 'model1', + query: '{query}', }, }, }, @@ -373,11 +296,10 @@ describe('create_query', () => { { standard: { query: { - text_expansion: { - field2: { - model_id: 'model1', - model_text: '{query}', - }, + sparse_vector: { + field: 'field2', + inference_id: 'model1', + query: '{query}', }, }, }, @@ -397,25 +319,23 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { elser_query_fields: [], - dense_vector_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + dense_vector_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], bm25_query_fields: ['content', 'title'], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, index2: { - elser_query_fields: [ - { field: 'field2', model_id: 'model1', nested: false, indices: ['index2'] }, - ], + elser_query_fields: [{ field: 'field2', model_id: 'model1', indices: ['index2'] }], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; - expect(createQuery(fields, fieldDescriptors)).toEqual({ + expect(createQuery(fields, sourceFields, fieldDescriptors)).toEqual({ retriever: { standard: { query: { @@ -444,16 +364,15 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { elser_query_fields: [], - dense_vector_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + dense_vector_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], bm25_query_fields: ['content', 'title'], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; - expect(createQuery(fields, fieldDescriptors)).toEqual({ + expect(createQuery(fields, sourceFields, fieldDescriptors)).toEqual({ retriever: { rrf: { retrievers: [ @@ -488,21 +407,262 @@ describe('create_query', () => { }, }); }); + + describe('semantic fields', () => { + describe('sparse_vector embedding', () => { + it('should return a query with semantic field, specified as a source field', () => { + // as the field is specified as a source field, it should use the nested query and manually calling the sparse_vector query + const fields = { + index1: ['field2', 'title', 'content'], + }; + + const fieldDescriptors: IndicesQuerySourceFields = { + index1: { + elser_query_fields: [], + dense_vector_query_fields: [ + { field: 'field1', model_id: 'model1', indices: ['index1'] }, + ], + bm25_query_fields: ['content', 'title'], + source_fields: [], + skipped_fields: 0, + semantic_fields: [ + { + field: 'field2', + inferenceId: 'model2', + indices: ['index1'], + embeddingType: 'sparse_vector', + }, + ], + }, + }; + + expect( + createQuery( + fields, + { + index1: ['field2'], + }, + fieldDescriptors + ) + ).toEqual({ + retriever: { + rrf: { + retrievers: [ + { + standard: { + query: { + nested: { + inner_hits: { _source: ['field2.inference.chunks.text'], size: 2 }, + path: 'field2.inference.chunks', + query: { + sparse_vector: { + field: 'field2.inference.chunks.embeddings', + inference_id: 'model2', + query: '{query}', + }, + }, + }, + }, + }, + }, + { + standard: { + query: { multi_match: { fields: ['title', 'content'], query: '{query}' } }, + }, + }, + ], + }, + }, + }); + }); + + it('should return a query with semantic field, specified not as a source field', () => { + // this should fallback to using the semantic field for querying + const fields = { + index1: ['field2', 'title', 'content'], + }; + + const fieldDescriptors: IndicesQuerySourceFields = { + index1: { + elser_query_fields: [], + dense_vector_query_fields: [ + { field: 'field1', model_id: 'model1', indices: ['index1'] }, + ], + bm25_query_fields: ['content', 'title'], + source_fields: [], + skipped_fields: 0, + semantic_fields: [ + { + field: 'field2', + inferenceId: 'model2', + indices: ['index1'], + embeddingType: 'sparse_vector', + }, + ], + }, + }; + + expect( + createQuery( + fields, + { + index1: ['content'], + }, + fieldDescriptors + ) + ).toEqual({ + retriever: { + rrf: { + retrievers: [ + { standard: { query: { semantic: { field: 'field2', query: '{query}' } } } }, + { + standard: { + query: { multi_match: { fields: ['title', 'content'], query: '{query}' } }, + }, + }, + ], + }, + }, + }); + }); + }); + + describe('dense embedding', () => { + it('should return a query with semantic field, specified as a source field', () => { + // as the field is specified as a source field, it should use the nested query and manually calling the knn query + const fields = { + index1: ['field2', 'title', 'content'], + }; + + const fieldDescriptors: IndicesQuerySourceFields = { + index1: { + elser_query_fields: [], + dense_vector_query_fields: [ + { field: 'field1', model_id: 'model1', indices: ['index1'] }, + ], + bm25_query_fields: ['content', 'title'], + source_fields: [], + skipped_fields: 0, + semantic_fields: [ + { + field: 'field2', + inferenceId: 'model2', + indices: ['index1'], + embeddingType: 'dense_vector', + }, + ], + }, + }; + + expect( + createQuery( + fields, + { + index1: ['field2'], + }, + fieldDescriptors + ) + ).toEqual({ + retriever: { + rrf: { + retrievers: [ + { + standard: { + query: { + nested: { + inner_hits: { _source: ['field2.inference.chunks.text'], size: 2 }, + path: 'field2.inference.chunks', + query: { + knn: { + field: 'field2.inference.chunks.embeddings', + query_vector_builder: { + text_embedding: { + model_id: 'model2', + model_text: '{query}', + }, + }, + }, + }, + }, + }, + }, + }, + { + standard: { + query: { multi_match: { fields: ['title', 'content'], query: '{query}' } }, + }, + }, + ], + }, + }, + }); + }); + + it('should return a query with semantic field, specified not as a source field', () => { + // this should fallback to using the semantic field for querying + const fields = { + index1: ['field2', 'title', 'content'], + }; + + const fieldDescriptors: IndicesQuerySourceFields = { + index1: { + elser_query_fields: [], + dense_vector_query_fields: [ + { field: 'field1', model_id: 'model1', indices: ['index1'] }, + ], + bm25_query_fields: ['content', 'title'], + source_fields: [], + skipped_fields: 0, + semantic_fields: [ + { + field: 'field2', + inferenceId: 'model2', + indices: ['index1'], + embeddingType: 'dense_vector', + }, + ], + }, + }; + + expect( + createQuery( + fields, + { + index1: ['content'], + }, + fieldDescriptors + ) + ).toEqual({ + retriever: { + rrf: { + retrievers: [ + { standard: { query: { semantic: { field: 'field2', query: '{query}' } } } }, + { + standard: { + query: { multi_match: { fields: ['title', 'content'], query: '{query}' } }, + }, + }, + ], + }, + }, + }); + }); + }); + }); }); describe('getDefaultQueryFields', () => { it('should return default ELSER query fields', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { - elser_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + elser_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], dense_vector_query_fields: [ - { field: 'field1', model_id: 'dense_model', nested: false, indices: ['index1'] }, + { field: 'field1', model_id: 'dense_model', indices: ['index1'] }, ], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; @@ -512,36 +672,34 @@ describe('create_query', () => { it('should return default elser query fields for multiple indices', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { - elser_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + elser_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], dense_vector_query_fields: [ { field: 'dv_field1', model_id: 'dense_model', - nested: false, + indices: ['index1', 'index2'], }, ], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, index2: { - elser_query_fields: [ - { field: 'vector', model_id: 'model1', nested: false, indices: ['index2'] }, - ], + elser_query_fields: [{ field: 'vector', model_id: 'model1', indices: ['index2'] }], dense_vector_query_fields: [ { field: 'dv_field1', model_id: 'dense_model', - nested: false, + indices: ['index1', 'index2'], }, ], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; @@ -554,36 +712,34 @@ describe('create_query', () => { it('should return elser query fields for default fields', () => { const fieldDescriptors: IndicesQuerySourceFields = { index1: { - elser_query_fields: [ - { field: 'field1', model_id: 'model1', nested: false, indices: ['index1'] }, - ], + elser_query_fields: [{ field: 'field1', model_id: 'model1', indices: ['index1'] }], dense_vector_query_fields: [ { field: 'dv_field1', model_id: 'dense_model', - nested: false, + indices: ['index1', 'index2'], }, ], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, index2: { - elser_query_fields: [ - { field: 'vector', model_id: 'model1', nested: false, indices: ['index2'] }, - ], + elser_query_fields: [{ field: 'vector', model_id: 'model1', indices: ['index2'] }], dense_vector_query_fields: [ { field: 'dv_field1', model_id: 'dense_model', - nested: false, + indices: ['index1', 'index2'], }, ], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; @@ -598,11 +754,12 @@ describe('create_query', () => { index1: { elser_query_fields: [], dense_vector_query_fields: [ - { field: 'dv_field1', model_id: 'dense_model', nested: false, indices: ['index1'] }, + { field: 'dv_field1', model_id: 'dense_model', indices: ['index1'] }, ], bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; @@ -617,6 +774,7 @@ describe('create_query', () => { bm25_query_fields: ['title', 'text', 'content'], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; @@ -633,6 +791,7 @@ describe('create_query', () => { bm25_query_fields: ['unknown1', 'unknown2'], source_fields: [], skipped_fields: 0, + semantic_fields: [], }, }; @@ -648,6 +807,7 @@ describe('create_query', () => { 'search-search-labs': { elser_query_fields: [], dense_vector_query_fields: [], + semantic_fields: [], bm25_query_fields: [ 'additional_urls', 'title', @@ -695,6 +855,7 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { 'search-search-labs': { elser_query_fields: [], + semantic_fields: [], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: [], @@ -713,6 +874,7 @@ describe('create_query', () => { const fieldDescriptors: IndicesQuerySourceFields = { 'search-search-labs': { elser_query_fields: [], + semantic_fields: [], dense_vector_query_fields: [], bm25_query_fields: [], source_fields: ['non_suggested_field'], diff --git a/x-pack/plugins/search_playground/public/utils/create_query.ts b/x-pack/plugins/search_playground/public/utils/create_query.ts index b2602a45707a85..0f65bea734d5cb 100644 --- a/x-pack/plugins/search_playground/public/utils/create_query.ts +++ b/x-pack/plugins/search_playground/public/utils/create_query.ts @@ -46,6 +46,7 @@ interface ReRankOptions { export function createQuery( fields: IndexFields, + sourceFields: IndexFields, fieldDescriptors: IndicesQuerySourceFields, rerankOptions: ReRankOptions = { rrf: true, @@ -57,19 +58,83 @@ export function createQuery( const indexFields: string[] = fields[index]; const indexFieldDescriptors: QuerySourceFields = fieldDescriptors[index]; + const semanticMatches = indexFields.map((field) => { + const semanticField = indexFieldDescriptors.semantic_fields.find((x) => x.field === field); + const isSourceField = sourceFields[index].includes(field); + + // this is needed to get the inner_hits for the source field + // we cant rely on only the semantic field + // in future inner_hits option will be added to semantic + if (semanticField && isSourceField) { + if (semanticField.embeddingType === 'dense_vector') { + const filter = + semanticField.indices.length < indices.length + ? { filter: { terms: { _index: semanticField.indices } } } + : {}; + + return { + nested: { + path: `${semanticField.field}.inference.chunks`, + query: { + knn: { + field: `${semanticField.field}.inference.chunks.embeddings`, + ...filter, + query_vector_builder: { + text_embedding: { + model_id: semanticField.inferenceId, + model_text: '{query}', + }, + }, + }, + }, + inner_hits: { + size: 2, + _source: [`${semanticField.field}.inference.chunks.text`], + }, + }, + }; + } else if (semanticField.embeddingType === 'sparse_vector') { + return { + nested: { + path: `${semanticField.field}.inference.chunks`, + query: { + sparse_vector: { + inference_id: semanticField.inferenceId, + field: `${semanticField.field}.inference.chunks.embeddings`, + query: '{query}', + }, + }, + inner_hits: { + size: 2, + _source: [`${semanticField.field}.inference.chunks.text`], + }, + }, + }; + } + } else if (semanticField) { + return { + semantic: { + field: semanticField.field, + query: '{query}', + }, + }; + } else { + return null; + } + }); + const sparseMatches = indexFields.map((field) => { const elserField = indexFieldDescriptors.elser_query_fields.find( (x) => x.field === field ); - // not supporting nested fields for now - if (elserField && !elserField.nested) { + if (elserField) { // when another index has the same field, we don't want to duplicate the match rule const hasExistingSparseMatch = acc.queryMatches.find( - (x: any) => - x?.text_expansion?.[field] && - x?.text_expansion?.[field].model_id === elserField?.model_id + (x) => + x?.sparse_vector?.field === field && + x?.sparse_vector?.inference_id === elserField?.model_id ); if (hasExistingSparseMatch) { @@ -77,11 +142,10 @@ export function createQuery( } return { - text_expansion: { - [elserField.field]: { - model_id: elserField.model_id, - model_text: '{query}', - }, + sparse_vector: { + field: elserField.field, + inference_id: elserField.model_id, + query: '{query}', }, }; } @@ -108,8 +172,7 @@ export function createQuery( (x) => x.field === field ); - // not supporting nested fields for now - if (denseVectorField && !denseVectorField.nested) { + if (denseVectorField) { // when the knn field isn't found in all indices, we need a filter to ensure we only use the field from the correct index const filter = denseVectorField.indices.length < indices.length @@ -134,7 +197,7 @@ export function createQuery( }) .filter((x) => !!x); - const matches = [...sparseMatches, bm25Match].filter((x) => !!x); + const matches = [...sparseMatches, ...semanticMatches, bm25Match].filter((x) => !!x); return { queryMatches: [...acc.queryMatches, ...matches], @@ -222,6 +285,14 @@ export function getDefaultSourceFields(fieldDescriptors: IndicesQuerySourceField (acc: IndexFields, index: string) => { const indexFieldDescriptors = fieldDescriptors[index]; + // semantic_text fields are prioritized + if (indexFieldDescriptors.semantic_fields.length > 0) { + return { + ...acc, + [index]: indexFieldDescriptors.semantic_fields.map((x) => x.field), + }; + } + // if there are no source fields, we don't need to suggest anything if (indexFieldDescriptors.source_fields.length === 0) { return { @@ -253,7 +324,9 @@ export function getDefaultQueryFields(fieldDescriptors: IndicesQuerySourceFields const indexFieldDescriptors = fieldDescriptors[index]; const fields: string[] = []; - if (indexFieldDescriptors.elser_query_fields.length > 0) { + if (indexFieldDescriptors.semantic_fields.length > 0) { + fields.push(...indexFieldDescriptors.semantic_fields.map((x) => x.field)); + } else if (indexFieldDescriptors.elser_query_fields.length > 0) { const suggested = indexFieldDescriptors.elser_query_fields.filter((x) => SUGGESTED_SPARSE_FIELDS.includes(x.field) ); diff --git a/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts b/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts index ddc95d9dd4346d..f7ad46d3fdfdad 100644 --- a/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts +++ b/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts @@ -208,6 +208,57 @@ describe('conversational chain', () => { }); }, 10000); + it('should be able to create a conversational chain with inner hit field', async () => { + await createTestChain({ + responses: ['the final answer'], + chat: [ + { + id: '1', + role: 'user', + content: 'what is the work from home policy?', + }, + ], + expectedFinalAnswer: 'the final answer', + docs: [ + { + _index: 'index', + _id: '1', + inner_hits: { + 'field.inference.chunks': { + hits: { + hits: [ + { + _source: { + text: 'value', + }, + }, + ], + }, + }, + }, + }, + ], + expectedDocs: [ + { + documents: [{ metadata: { _id: '1', _index: 'index' }, pageContent: 'value' }], + type: 'retrieved_docs', + }, + ], + expectedTokens: [ + { type: 'context_token_count', count: 7 }, + { type: 'prompt_token_count', count: 20 }, + ], + expectedSearchRequest: [ + { + method: 'POST', + path: '/index,website/_search', + body: { query: { match: { field: 'what is the work from home policy?' } }, size: 3 }, + }, + ], + contentField: { index: 'field' }, + }); + }, 10000); + it('asking with chat history should re-write the question', async () => { await createTestChain({ responses: ['rewrite the question', 'the final answer'], diff --git a/x-pack/plugins/search_playground/server/lib/elasticsearch_retriever.ts b/x-pack/plugins/search_playground/server/lib/elasticsearch_retriever.ts index 4a2c3344b29342..8504651bb6398b 100644 --- a/x-pack/plugins/search_playground/server/lib/elasticsearch_retriever.ts +++ b/x-pack/plugins/search_playground/server/lib/elasticsearch_retriever.ts @@ -89,7 +89,7 @@ export class ElasticsearchRetriever extends BaseRetriever { : this.content_field[hit._index as string]; // we need to iterate over the _source object to get the value of complex key definition such as metadata.source - const valueForSelectedField = getValueForSelectedField(hit._source, pageContentFieldKey); + const valueForSelectedField = getValueForSelectedField(hit, pageContentFieldKey); return new Document({ pageContent: valueForSelectedField, diff --git a/x-pack/plugins/search_playground/server/lib/fetch_query_source_fields.test.ts b/x-pack/plugins/search_playground/server/lib/fetch_query_source_fields.test.ts index 539a3deaa7c032..8991cb99244800 100644 --- a/x-pack/plugins/search_playground/server/lib/fetch_query_source_fields.test.ts +++ b/x-pack/plugins/search_playground/server/lib/fetch_query_source_fields.test.ts @@ -19,8 +19,13 @@ import { SPARSE_INPUT_OUTPUT_ONE_INDEX, SPARSE_INPUT_OUTPUT_ONE_INDEX_FIELD_CAPS, SPARSE_INPUT_OUTPUT_ONE_INDEX_FIELD_CAPS_MODEL_ID_KEYWORD, + SPARSE_SEMANTIC_FIELD_FIELD_CAPS, + SPARSE_SEMANTIC_FIELD_MAPPINGS, DENSE_SPARSE_SAME_FIELD_NAME_CAPS, DENSE_SPARSE_SAME_FIELD_NAME_DOCS, + DENSE_SEMANTIC_FIELD_MAPPINGS, + DENSE_SEMANTIC_FIELD_FIELD_CAPS, + DENSE_SEMANTIC_FIELD_MAPPINGS_MISSING_TASK_TYPE, } from '../../__mocks__/fetch_query_source_fields.mock'; import { fetchFields, @@ -36,10 +41,20 @@ describe('fetch_query_source_fields', () => { { index: 'workplace_index', doc: ELSER_PASSAGE_CHUNKED_TWO_INDICES_DOCS[0], + mapping: { + workplace_index: { + mappings: {}, + }, + }, }, { index: 'workplace_index2', doc: ELSER_PASSAGE_CHUNKED_TWO_INDICES_DOCS[1], + mapping: { + workplace_index2: { + mappings: {}, + }, + }, }, ]) ).toEqual({ @@ -55,14 +70,15 @@ describe('fetch_query_source_fields', () => { { field: 'vector.tokens', model_id: '.elser_model_2', - nested: false, indices: ['workplace_index'], }, ], skipped_fields: 8, source_fields: ['metadata.summary', 'metadata.rolePermissions', 'text', 'metadata.name'], + semantic_fields: [], }, workplace_index2: { + semantic_fields: [], bm25_query_fields: [ 'metadata.summary', 'content', @@ -75,7 +91,6 @@ describe('fetch_query_source_fields', () => { { field: 'content_vector.tokens', model_id: '.elser_model_2', - nested: false, indices: ['workplace_index2'], }, ], @@ -95,10 +110,16 @@ describe('fetch_query_source_fields', () => { { index: 'search-example-main', doc: DENSE_PASSAGE_FIRST_SINGLE_INDEX_DOC, + mapping: { + 'search-example-main': { + mappings: {}, + }, + }, }, ]) ).toEqual({ 'search-example-main': { + semantic_fields: [], bm25_query_fields: [ 'page_content_key', 'title', @@ -118,7 +139,6 @@ describe('fetch_query_source_fields', () => { { field: 'page_content_e5_embbeding.predicted_value', model_id: '.multilingual-e5-small_linux-x86_64', - nested: false, indices: ['search-example-main'], }, ], @@ -149,18 +169,23 @@ describe('fetch_query_source_fields', () => { { index: 'search-nethys', doc: SPARSE_DOC_SINGLE_INDEX, + mapping: { + 'search-nethys': { + mappings: {}, + }, + }, }, ]) ).toEqual({ 'search-nethys': { bm25_query_fields: ['body_content', 'headings', 'title'], dense_vector_query_fields: [], + semantic_fields: [], elser_query_fields: [ { field: 'ml.inference.body_content_expanded.predicted_value', indices: ['search-nethys'], model_id: '.elser_model_2_linux-x86_64', - nested: false, }, ], source_fields: ['body_content', 'headings', 'title'], @@ -176,6 +201,11 @@ describe('fetch_query_source_fields', () => { { index: 'workplace_index_nested', doc: DENSE_VECTOR_DOCUMENT_FIRST[0], + mapping: { + workplace_index_nested: { + mappings: {}, + }, + }, }, ]) ).toEqual({ @@ -192,6 +222,7 @@ describe('fetch_query_source_fields', () => { ], dense_vector_query_fields: [], elser_query_fields: [], + semantic_fields: [], source_fields: [ 'metadata.category', 'content', @@ -213,6 +244,11 @@ describe('fetch_query_source_fields', () => { { index: 'index2', doc: DENSE_INPUT_OUTPUT_ONE_INDEX[0], + mapping: { + index2: { + mappings: {}, + }, + }, }, ]) ).toEqual({ @@ -223,10 +259,10 @@ describe('fetch_query_source_fields', () => { field: 'text_embedding', indices: ['index2'], model_id: '.multilingual-e5-small', - nested: false, }, ], elser_query_fields: [], + semantic_fields: [], source_fields: ['text'], skipped_fields: 2, }, @@ -239,6 +275,11 @@ describe('fetch_query_source_fields', () => { { index: 'index', doc: SPARSE_INPUT_OUTPUT_ONE_INDEX[0], + mapping: { + index: { + mappings: {}, + }, + }, }, ]) ).toEqual({ @@ -249,10 +290,10 @@ describe('fetch_query_source_fields', () => { field: 'text_embedding', indices: ['index'], model_id: '.elser_model_2', - nested: false, }, ], dense_vector_query_fields: [], + semantic_fields: [], source_fields: ['text'], skipped_fields: 2, }, @@ -265,10 +306,20 @@ describe('fetch_query_source_fields', () => { { index: 'cohere-embeddings', doc: DENSE_SPARSE_SAME_FIELD_NAME_DOCS[0], + mapping: { + 'cohere-embeddings': { + mappings: {}, + }, + }, }, { index: 'elser_index', doc: DENSE_SPARSE_SAME_FIELD_NAME_DOCS[1], + mapping: { + elser_index: { + mappings: {}, + }, + }, }, ]) ).toEqual({ @@ -279,12 +330,12 @@ describe('fetch_query_source_fields', () => { field: 'text_embedding', indices: ['cohere-embeddings'], model_id: 'cohere_embeddings', - nested: false, }, ], elser_query_fields: [], skipped_fields: 2, source_fields: ['text'], + semantic_fields: [], }, elser_index: { bm25_query_fields: ['text'], @@ -294,14 +345,96 @@ describe('fetch_query_source_fields', () => { field: 'text_embedding', indices: ['elser_index'], model_id: 'my-elser-model', - nested: false, }, ], skipped_fields: 2, source_fields: ['text'], + semantic_fields: [], }, }); }); + + describe('semantic text support', () => { + it('should return the correct fields for semantic text - sparse', () => { + expect( + parseFieldsCapabilities(SPARSE_SEMANTIC_FIELD_FIELD_CAPS, [ + { + index: 'test-index2', + // unused + doc: SPARSE_INPUT_OUTPUT_ONE_INDEX[0], + mapping: SPARSE_SEMANTIC_FIELD_MAPPINGS, + }, + ]) + ).toEqual({ + 'test-index2': { + bm25_query_fields: ['non_infer_field'], + dense_vector_query_fields: [], + elser_query_fields: [], + semantic_fields: [ + { + embeddingType: 'sparse_vector', + field: 'infer_field', + inferenceId: 'elser-endpoint', + indices: ['test-index2'], + }, + ], + skipped_fields: 4, + source_fields: ['infer_field', 'non_infer_field'], + }, + }); + }); + + it('should return the correct fields for semantic text - dense', () => { + expect( + parseFieldsCapabilities(DENSE_SEMANTIC_FIELD_FIELD_CAPS, [ + { + index: 'test-index2', + // unused + doc: DENSE_INPUT_OUTPUT_ONE_INDEX[0], + mapping: DENSE_SEMANTIC_FIELD_MAPPINGS, + }, + ]) + ).toEqual({ + 'test-index2': { + bm25_query_fields: ['non_infer_field'], + dense_vector_query_fields: [], + elser_query_fields: [], + semantic_fields: [ + { + embeddingType: 'dense_vector', + field: 'infer_field', + inferenceId: 'cohere', + indices: ['test-index2'], + }, + ], + skipped_fields: 4, + source_fields: ['infer_field', 'non_infer_field'], + }, + }); + }); + + it('skips if the semantic_text field not setup correctly', () => { + expect( + parseFieldsCapabilities(DENSE_SEMANTIC_FIELD_FIELD_CAPS, [ + { + index: 'test-index2', + // unused + doc: DENSE_INPUT_OUTPUT_ONE_INDEX[0], + mapping: DENSE_SEMANTIC_FIELD_MAPPINGS_MISSING_TASK_TYPE, + }, + ]) + ).toEqual({ + 'test-index2': { + bm25_query_fields: ['non_infer_field'], + dense_vector_query_fields: [], + elser_query_fields: [], + semantic_fields: [], + skipped_fields: 5, // increat by 1 for the semantic field + source_fields: ['non_infer_field'], + }, + }); + }); + }); }); describe('getModelIdFields', () => { @@ -340,6 +473,13 @@ describe('fetch_query_source_fields', () => { asCurrentUser: { fieldCaps: jest.fn().mockResolvedValue(DENSE_PASSAGE_FIRST_SINGLE_INDEX_FIELD_CAPS), search: jest.fn().mockResolvedValue(DENSE_PASSAGE_FIRST_SINGLE_INDEX_DOC), + indices: { + getMapping: jest.fn().mockResolvedValue({ + 'search-example-main': { + mappings: {}, + }, + }), + }, }, } as any; const indices = ['search-example-main']; @@ -371,6 +511,13 @@ describe('fetch_query_source_fields', () => { asCurrentUser: { fieldCaps: jest.fn().mockResolvedValue(SPARSE_INPUT_OUTPUT_ONE_INDEX_FIELD_CAPS), search: jest.fn().mockResolvedValue(SPARSE_INPUT_OUTPUT_ONE_INDEX), + indices: { + getMapping: jest.fn().mockResolvedValue({ + index: { + mappings: {}, + }, + }), + }, }, } as any; const indices = ['index']; diff --git a/x-pack/plugins/search_playground/server/lib/fetch_query_source_fields.ts b/x-pack/plugins/search_playground/server/lib/fetch_query_source_fields.ts index 82db1b8de6df41..15e1ead0bf037d 100644 --- a/x-pack/plugins/search_playground/server/lib/fetch_query_source_fields.ts +++ b/x-pack/plugins/search_playground/server/lib/fetch_query_source_fields.ts @@ -5,8 +5,14 @@ * 2.0. */ -import { SearchResponse, FieldCapsResponse } from '@elastic/elasticsearch/lib/api/types'; -import { FieldCapsFieldCapability } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { + SearchResponse, + FieldCapsResponse, + IndicesGetMappingResponse, + FieldCapsFieldCapability, + MappingPropertyBase, +} from '@elastic/elasticsearch/lib/api/types'; + import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import { IndicesQuerySourceFields } from '../types'; @@ -15,11 +21,35 @@ interface FieldModelId { modelId: string | undefined; } +type SemanticEmbeddingType = 'sparse_vector' | 'dense_vector'; + +interface SemanticField { + field: string; + inferenceId: string; + embeddingType?: SemanticEmbeddingType; +} + interface IndexFieldModel { index: string; fields: FieldModelId[]; + semanticTextFields: SemanticField[]; } +type TaskType = 'sparse_embedding' | 'text_embedding'; + +interface MappingSemanticTextProperty extends MappingPropertyBase { + type: 'semantic_text'; + inference_id: string; + model_settings?: { + task_type: TaskType; + }; +} + +const EMBEDDING_TYPE: Record = { + sparse_embedding: 'sparse_vector', + text_embedding: 'dense_vector', +}; + export const getModelIdFields = (fieldCapsResponse: FieldCapsResponse) => { const { fields } = fieldCapsResponse; return Object.keys(fields).reduce>((acc, fieldKey) => { @@ -64,7 +94,7 @@ export const fetchFields = async ( const modelIdFields = getModelIdFields(fieldCapabilities); - const indicesAggs = await Promise.all( + const indicesAggsMappings = await Promise.all( indices.map(async (index) => ({ index, doc: await client.asCurrentUser.search({ @@ -85,14 +115,19 @@ export const fetchFields = async ( ), }, }), + mapping: await client.asCurrentUser.indices.getMapping({ index }), })) ); - return parseFieldsCapabilities(fieldCapabilities, indicesAggs); + return parseFieldsCapabilities(fieldCapabilities, indicesAggsMappings); }; const INFERENCE_MODEL_FIELD_REGEXP = /\.predicted_value|\.tokens/; +const getSemanticField = (field: string, semanticFields: SemanticField[]) => { + return semanticFields.find((sf) => sf.field === field); +}; + const getModelField = (field: string, modelIdFields: FieldModelId[]) => { // For input_output inferred fields, the model_id is at the top level const topLevelModelField = modelIdFields.find( @@ -141,12 +176,12 @@ const isFieldInIndex = ( export const parseFieldsCapabilities = ( fieldCapsResponse: FieldCapsResponse, - aggDocs: Array<{ index: string; doc: SearchResponse }> + aggMappingDocs: Array<{ index: string; doc: SearchResponse; mapping: IndicesGetMappingResponse }> ): IndicesQuerySourceFields => { const { fields, indices: indexOrIndices } = fieldCapsResponse; const indices = Array.isArray(indexOrIndices) ? indexOrIndices : [indexOrIndices]; - const indexModelIdFields = aggDocs.map((aggDoc) => { + const indexModelIdFields = aggMappingDocs.map((aggDoc) => { const modelIdFields = Object.keys(aggDoc.doc.aggregations || {}).map((field) => { return { field, @@ -154,9 +189,28 @@ export const parseFieldsCapabilities = ( }; }); + const mappingProperties = aggDoc.mapping[aggDoc.index].mappings.properties || {}; + + const semanticTextFields: SemanticField[] = Object.keys(mappingProperties || {}) + .filter( + // @ts-ignore + (field) => mappingProperties[field].type === 'semantic_text' + ) + .map((field) => { + const mapping = mappingProperties[field] as unknown as MappingSemanticTextProperty; + return { + field, + inferenceId: mapping?.inference_id, + embeddingType: mapping?.model_settings?.task_type + ? EMBEDDING_TYPE[mapping.model_settings.task_type] + : undefined, + }; + }); + return { index: aggDoc.index, fields: modelIdFields, + semanticTextFields, }; }); @@ -167,6 +221,7 @@ export const parseFieldsCapabilities = ( bm25_query_fields: [], source_fields: [], skipped_fields: 0, + semantic_fields: [], }; return acc; }, {}); @@ -186,15 +241,38 @@ export const parseFieldsCapabilities = ( : (indices as unknown as string[]); for (const index of indicesPresentIn) { - const modelIdFields = indexModelIdFields.find( + const { fields: modelIdFields, semanticTextFields } = indexModelIdFields.find( (indexModelIdField) => indexModelIdField.index === index - )!.fields; + )!; + const nestedField = isFieldNested(fieldKey, fieldCapsResponse); + + if (isFieldInIndex(field, 'semantic_text', index)) { + const semanticFieldMapping = getSemanticField(fieldKey, semanticTextFields); - if ( + // only use this when embeddingType and inferenceId is defined + // this requires semantic_text field to be set up correctly and ingested + if ( + semanticFieldMapping && + semanticFieldMapping.embeddingType && + semanticFieldMapping.inferenceId && + !nestedField + ) { + const semanticField = { + field: fieldKey, + inferenceId: semanticFieldMapping.inferenceId, + embeddingType: semanticFieldMapping.embeddingType, + indices: (field.semantic_text.indices as string[]) || indicesPresentIn, + }; + + acc[index].semantic_fields.push(semanticField); + acc[index].source_fields.push(fieldKey); + } else { + acc[index].skipped_fields++; + } + } else if ( isFieldInIndex(field, 'rank_features', index) || isFieldInIndex(field, 'sparse_vector', index) ) { - const nestedField = isFieldNested(fieldKey, fieldCapsResponse); const modelId = getModelField(fieldKey, modelIdFields); const fieldCapabilities = field.rank_features || field.sparse_vector; @@ -205,7 +283,6 @@ export const parseFieldsCapabilities = ( const elserModelField = { field: fieldKey, model_id: modelId, - nested: !!isFieldNested(fieldKey, fieldCapsResponse), indices: (fieldCapabilities.indices as string[]) || indicesPresentIn, }; acc[index].elser_query_fields.push(elserModelField); @@ -213,7 +290,6 @@ export const parseFieldsCapabilities = ( acc[index].skipped_fields++; } } else if (isFieldInIndex(field, 'dense_vector', index)) { - const nestedField = isFieldNested(fieldKey, fieldCapsResponse); const modelId = getModelField(fieldKey, modelIdFields); const fieldCapabilities = field.dense_vector; @@ -224,7 +300,6 @@ export const parseFieldsCapabilities = ( const denseVectorField = { field: fieldKey, model_id: modelId, - nested: !!nestedField, indices: (fieldCapabilities.indices as string[]) || indicesPresentIn, }; acc[index].dense_vector_query_fields.push(denseVectorField); diff --git a/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.test.ts b/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.test.ts index a13e51603cc7b6..bf02f6620d38ca 100644 --- a/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.test.ts +++ b/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.test.ts @@ -22,7 +22,7 @@ describe('getValueForSelectedField', () => { }, }; - expect(getValueForSelectedField(hit._source, 'test')).toEqual('The Shawshank Redemption'); + expect(getValueForSelectedField(hit, 'test')).toEqual('The Shawshank Redemption'); }); test('should return for combined key', () => { @@ -39,7 +39,7 @@ describe('getValueForSelectedField', () => { }, }; - expect(getValueForSelectedField(hit._source, 'metadata.source')).toEqual( + expect(getValueForSelectedField(hit, 'metadata.source')).toEqual( 'Over the course of several years, two convicts form a friendship, seeking consolation and, eventually, redemption through basic compassion' ); }); @@ -58,7 +58,7 @@ describe('getValueForSelectedField', () => { }, }; - expect(getValueForSelectedField(hit._source, 'metadata.sources')).toBe(''); + expect(getValueForSelectedField(hit, 'metadata.sources')).toBe(''); }); test('should return empty string for nested key', () => { @@ -75,6 +75,52 @@ describe('getValueForSelectedField', () => { }, }; - expect(getValueForSelectedField(hit._source, 'bla.sources')).toBe(''); + expect(getValueForSelectedField(hit, 'bla.sources')).toBe(''); + }); + + test('should return when its a chunked passage', () => { + const hit = { + _index: 'sample-index', + _id: '8jSNY48B6iHEi98DL1C-', + _score: 0.7789394, + _source: { + test: 'The Shawshank Redemption', + metadata: { + source: + 'Over the course of several years, two convicts form a friendship, seeking consolation and, eventually, redemption through basic compassion', + }, + }, + inner_hits: { + 'test.inference.chunks': { + hits: { + hits: [ + { + _source: { + text: 'Over the course of several years', + }, + }, + { + _source: { + text: 'two convicts form a friendship', + }, + }, + { + _source: { + text: 'seeking consolation and, eventually, redemption through basic compassion', + }, + }, + ], + }, + }, + }, + }; + + expect(getValueForSelectedField(hit as any, 'test')).toMatchInlineSnapshot(` + "Over the course of several years + --- + two convicts form a friendship + --- + seeking consolation and, eventually, redemption through basic compassion" + `); }); }); diff --git a/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.ts b/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.ts index 6a2044f2943e45..68bd600d62143b 100644 --- a/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.ts +++ b/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.ts @@ -5,8 +5,20 @@ * 2.0. */ +import { SearchHit } from '@elastic/elasticsearch/lib/api/types'; import { get } from 'lodash'; -export const getValueForSelectedField = (source: unknown, path: string): string => { - return get(source, path, ''); +export const getValueForSelectedField = (hit: SearchHit, path: string): string => { + if (!hit) { + return ''; + } + + // for semantic_text matches + if (!!hit.inner_hits?.[`${path}.inference.chunks`]) { + return hit.inner_hits[`${path}.inference.chunks`].hits.hits + .map((innerHit) => innerHit._source.text) + .join('\n --- \n'); + } + + return get(hit._source, path, ''); }; From b169a9c729e71aa7d865dad5f87852c77941d5a4 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 18 Jun 2024 17:54:29 +0200 Subject: [PATCH 039/123] [Security Solution] Add missing alerts (signals) API endpoints OpenAPI specs (#184838) **Addresses:** https://github.com/elastic/kibana/issues/183661 ## Summary This PR adds missing OpenAPI specs for the following API endpoints (Alerts API and Alerts Migration API) available in both Serverless and ESS - `POST /api/detection_engine/signals/status` - `POST /api/detection_engine/signals/tags` - `POST /api/detection_engine/signals/search` and API endpoints available only in ESS - `POST /api/detection_engine/signals/migration_status` - `POST /api/detection_engine/signals/migration` - `POST /api/detection_engine/signals/finalize_migration` - `DELETE /api/detection_engine/signals/migration` **Note:** Code generation is enabled for the added specs to verify that it works and produces expected results. Generated Zod schemas and types aren't integrated in the route's code. --- .../api/detection_engine/alert_tags/index.ts | 2 +- .../set_alert_tags/set_alert_tags.gen.ts | 38 +++++ .../set_alert_tags/set_alert_tags.schema.yaml | 70 +++++++++ .../set_alert_tags_route.mock.ts | 4 +- .../set_alert_tags/set_alert_tags_route.ts | 20 --- .../api/detection_engine/signals/index.ts | 5 +- .../query_signals/query_signals_route.gen.ts | 45 ++++++ .../query_signals_route.schema.yaml | 93 ++++++++++++ .../query_signals/query_signals_route.test.ts | 140 ------------------ .../query_signals/query_signals_route.ts | 25 ---- .../set_signal_status_route.test.ts | 83 ----------- .../set_signal_status_route.ts | 24 --- .../set_signal_status_type_dependents.test.ts | 47 ------ .../set_signal_status_type_dependents.ts | 22 --- .../set_signals_status_route.gen.ts | 43 ++++++ .../set_signals_status_route.schema.yaml | 81 ++++++++++ .../create_signals_migration.gen.ts | 64 ++++++++ .../create_signals_migration.schema.yaml | 120 +++++++++++++++ .../create_signals_migration_route.mock.ts | 4 +- .../create_signals_migration_route.ts | 29 ---- .../delete_signals_migration.gen.ts | 44 ++++++ .../delete_signals_migration.schema.yaml | 100 +++++++++++++ .../delete_signals_migration_route.ts | 14 -- .../finalize_signals_migration.gen.ts | 45 ++++++ .../finalize_signals_migration.schema.yaml | 101 +++++++++++++ .../finalize_signals_migration_route.mock.ts | 4 +- .../finalize_signals_migration_route.ts | 16 -- .../get_signals_migration_status.gen.ts | 61 ++++++++ .../get_signals_migration_status.schema.yaml | 114 ++++++++++++++ ...get_signals_migration_status_route.mock.ts | 4 +- .../get_signals_migration_status_route.ts | 18 --- .../signals_migration/index.ts | 8 +- .../common/api/model/alert.gen.ts | 11 ++ .../common/api/model/alert.schema.yaml | 16 ++ .../common/api/model/error_responses.gen.ts | 30 ++++ .../api/model/error_responses.schema.yaml | 32 ++++ .../migrations/create_migration.ts | 6 +- .../migrations/migration_service.ts | 4 +- .../routes/__mocks__/request_responses.ts | 23 +-- .../create_signals_migration_route.test.ts | 4 +- .../signals/create_signals_migration_route.ts | 8 +- .../signals/delete_signals_migration_route.ts | 8 +- .../finalize_signals_migration_route.ts | 8 +- .../get_signals_migration_status_route.ts | 8 +- .../routes/signals/open_close_signals.test.ts | 22 +-- .../signals/open_close_signals_route.ts | 40 +++-- .../routes/signals/query_signals_route.ts | 14 +- .../signals/set_alert_tags_route.test.ts | 15 +- .../routes/signals/set_alert_tags_route.ts | 10 +- .../services/security_solution_api.gen.ts | 98 ++++++++++++ .../migrations/create_alerts_migrations.ts | 13 +- .../field_aliases.ts | 5 +- .../query_alerts.ts | 8 +- .../set_alert_tags.ts | 19 +-- .../utils/alerts/set_alert_tags.ts | 4 +- 55 files changed, 1325 insertions(+), 569 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.schema.yaml delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags_route.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.schema.yaml delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.test.ts delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.ts delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_route.test.ts delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_route.ts delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_type_dependents.test.ts delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_type_dependents.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.schema.yaml create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.schema.yaml delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.schema.yaml delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration_route.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.schema.yaml delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration_route.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.schema.yaml delete mode 100644 x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status_route.ts create mode 100644 x-pack/plugins/security_solution/common/api/model/error_responses.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/model/error_responses.schema.yaml diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/index.ts index 7adc565a09c8e4..0e4f6a7ae6609b 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export * from './set_alert_tags/set_alert_tags_route'; +export * from './set_alert_tags/set_alert_tags.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.gen.ts new file mode 100644 index 00000000000000..3640d78cd33b2a --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.gen.ts @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Manage alert tags API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { AlertIds, AlertTags } from '../../../model/alert.gen'; + +export type ManageAlertTags = z.infer; +export const ManageAlertTags = z.object({ + tags_to_add: AlertTags, + tags_to_remove: AlertTags, +}); + +export type ManageAlertTagsRequestBody = z.infer; +export const ManageAlertTagsRequestBody = z.object({ + ids: AlertIds, + tags: ManageAlertTags, +}); +export type ManageAlertTagsRequestBodyInput = z.input; + +/** + * Elasticsearch update by query response + */ +export type ManageAlertTagsResponse = z.infer; +export const ManageAlertTagsResponse = z.object({}).catchall(z.unknown()); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.schema.yaml new file mode 100644 index 00000000000000..ca2c93b88b25ef --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.schema.yaml @@ -0,0 +1,70 @@ +openapi: 3.0.0 +info: + title: Manage alert tags API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/tags: + post: + x-labels: [serverless, ess] + operationId: ManageAlertTags + x-codegen-enabled: true + summary: Manage alert tags for a one or more alerts + tags: + - Alerts API + requestBody: + description: An object containing tags to add or remove and alert ids the changes will be applied + required: true + content: + application/json: + schema: + type: object + properties: + ids: + $ref: '../../../model/alert.schema.yaml#/components/schemas/AlertIds' + tags: + $ref: '#/components/schemas/ManageAlertTags' + required: + - ids + - tags + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + additionalProperties: true + description: Elasticsearch update by query response + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + ManageAlertTags: + type: object + properties: + tags_to_add: + $ref: '../../../model/alert.schema.yaml#/components/schemas/AlertTags' + tags_to_remove: + $ref: '../../../model/alert.schema.yaml#/components/schemas/AlertTags' + required: + - tags_to_add + - tags_to_remove diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags_route.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags_route.mock.ts index f1e05ad7f125a9..a14b36fb7b2c56 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags_route.mock.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags_route.mock.ts @@ -5,13 +5,13 @@ * 2.0. */ -import type { SetAlertTagsRequestBody } from './set_alert_tags_route'; +import type { ManageAlertTagsRequestBody } from './set_alert_tags.gen'; export const getSetAlertTagsRequestMock = ( tagsToAdd: string[] = [], tagsToRemove: string[] = [], ids: string[] = [] -): SetAlertTagsRequestBody => ({ +): ManageAlertTagsRequestBody => ({ tags: { tags_to_add: tagsToAdd, tags_to_remove: tagsToRemove }, ids, }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags_route.ts deleted file mode 100644 index 8a6f93c20b7702..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags_route.ts +++ /dev/null @@ -1,20 +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 * as t from 'io-ts'; - -import { alert_tag_ids, alert_tags } from '../../model'; - -export const setAlertTagsRequestBody = t.exact( - t.type({ - tags: alert_tags, - ids: alert_tag_ids, - }) -); - -export type SetAlertTagsRequestBody = t.TypeOf; -export type SetAlertTagsRequestBodyDecoded = SetAlertTagsRequestBody; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals/index.ts index 636728ee2525db..97f441030bb485 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals/index.ts @@ -5,6 +5,5 @@ * 2.0. */ -export * from './query_signals/query_signals_route'; -export * from './set_signal_status/set_signal_status_route'; -export * from './set_signal_status/set_signal_status_type_dependents'; +export * from './query_signals/query_signals_route.gen'; +export * from './set_signal_status/set_signals_status_route.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.gen.ts new file mode 100644 index 00000000000000..67c5a695d19494 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.gen.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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Alerts search API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +export type AlertsSortCombinations = z.infer; +export const AlertsSortCombinations = z.union([z.string(), z.object({}).catchall(z.unknown())]); + +export type AlertsSort = z.infer; +export const AlertsSort = z.union([AlertsSortCombinations, z.array(AlertsSortCombinations)]); + +/** + * Elasticsearch query and aggregation request + */ +export type SearchAlertsRequestBody = z.infer; +export const SearchAlertsRequestBody = z.object({ + query: z.object({}).catchall(z.unknown()).optional(), + aggs: z.object({}).catchall(z.unknown()).optional(), + size: z.number().int().min(0).optional(), + track_total_hits: z.boolean().optional(), + _source: z.union([z.boolean(), z.string(), z.array(z.string())]).optional(), + fields: z.array(z.string()).optional(), + runtime_mappings: z.object({}).catchall(z.unknown()).optional(), + sort: AlertsSort.optional(), +}); +export type SearchAlertsRequestBodyInput = z.input; + +/** + * Elasticsearch search response + */ +export type SearchAlertsResponse = z.infer; +export const SearchAlertsResponse = z.object({}).catchall(z.unknown()); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.schema.yaml new file mode 100644 index 00000000000000..cd70e4b0c40717 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.schema.yaml @@ -0,0 +1,93 @@ +openapi: 3.0.0 +info: + title: Alerts search API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/search: + post: + x-labels: [serverless, ess] + operationId: SearchAlerts + x-codegen-enabled: true + summary: Find and/or aggregate detection alerts that match the given query + tags: + - Alerts API + requestBody: + description: Search and/or aggregation query + required: true + content: + application/json: + schema: + type: object + properties: + query: + type: object + additionalProperties: true + aggs: + type: object + additionalProperties: true + size: + type: integer + minimum: 0 + track_total_hits: + type: boolean + _source: + oneOf: + - type: boolean + - type: string + - type: array + items: + type: string + fields: + type: array + items: + type: string + runtime_mappings: + type: object + additionalProperties: true + sort: + $ref: '#/components/schemas/AlertsSort' + description: Elasticsearch query and aggregation request + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + additionalProperties: true + description: Elasticsearch search response + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + AlertsSortCombinations: + anyOf: + - type: string + - type: object + additionalProperties: true + + AlertsSort: + oneOf: + - $ref: '#/components/schemas/AlertsSortCombinations' + - type: array + items: + $ref: '#/components/schemas/AlertsSortCombinations' diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.test.ts deleted file mode 100644 index 6afdc9a07e8ab8..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.test.ts +++ /dev/null @@ -1,140 +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 { QuerySignalsSchema } from './query_signals_route'; -import { querySignalsSchema } from './query_signals_route'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; - -describe('query, aggs, size, _source and track_total_hits on signals index', () => { - test('query, aggs, size, _source and track_total_hits simultaneously', () => { - const payload: QuerySignalsSchema = { - query: {}, - aggs: {}, - size: 1, - track_total_hits: true, - _source: ['field'], - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('query, only', () => { - const payload: QuerySignalsSchema = { - query: {}, - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('aggs only', () => { - const payload: QuerySignalsSchema = { - aggs: {}, - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('size only', () => { - const payload: QuerySignalsSchema = { - size: 1, - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('track_total_hits only', () => { - const payload: QuerySignalsSchema = { - track_total_hits: true, - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('_source only (as string)', () => { - const payload: QuerySignalsSchema = { - _source: 'field', - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('_source only (as string[])', () => { - const payload: QuerySignalsSchema = { - _source: ['field'], - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('_source only (as boolean)', () => { - const payload: QuerySignalsSchema = { - _source: false, - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('fields only', () => { - const payload: QuerySignalsSchema = { - fields: ['test*'], - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('sort only', () => { - const payload: QuerySignalsSchema = { - sort: { - '@payload': 'desc', - }, - }; - - const decoded = querySignalsSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); -}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.ts deleted file mode 100644 index 7c0283f3f2a80e..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; - -export const querySignalsSchema = t.exact( - t.partial({ - query: t.object, - aggs: t.object, - size: PositiveInteger, - track_total_hits: t.boolean, - _source: t.union([t.boolean, t.string, t.array(t.string)]), - fields: t.array(t.string), - runtime_mappings: t.unknown, - sort: t.object, - }) -); - -export type QuerySignalsSchema = t.TypeOf; -export type QuerySignalsSchemaDecoded = QuerySignalsSchema; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_route.test.ts deleted file mode 100644 index 3f9e432fbc4f9b..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_route.test.ts +++ /dev/null @@ -1,83 +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 { SetSignalsStatusSchema } from './set_signal_status_route'; -import { setSignalsStatusSchema } from './set_signal_status_route'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { left } from 'fp-ts/lib/Either'; - -describe('set signal status schema', () => { - test('signal_ids and status is valid', () => { - const payload: SetSignalsStatusSchema = { - signal_ids: ['somefakeid'], - status: 'open', - }; - - const decoded = setSignalsStatusSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('query and status is valid', () => { - const payload: SetSignalsStatusSchema = { - query: {}, - status: 'open', - }; - - const decoded = setSignalsStatusSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('signal_ids and missing status is invalid', () => { - const payload: Omit = { - signal_ids: ['somefakeid'], - }; - - const decoded = setSignalsStatusSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "status"', - ]); - expect(message.schema).toEqual({}); - }); - - test('query and missing status is invalid', () => { - const payload: Omit = { - query: {}, - }; - - const decoded = setSignalsStatusSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "status"', - ]); - expect(message.schema).toEqual({}); - }); - - test('signal_ids is present but status has wrong value', () => { - const payload: Omit & { status: 'fakeVal' } = { - query: {}, - status: 'fakeVal', - }; - - const decoded = setSignalsStatusSchema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "fakeVal" supplied to "status"', - ]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_route.ts deleted file mode 100644 index 78d62031d5eb32..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_route.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 * as t from 'io-ts'; - -import { conflicts, signal_ids, signal_status_query, status } from '../../model'; - -export const setSignalsStatusSchema = t.intersection([ - t.type({ - status, - }), - t.partial({ - conflicts, - signal_ids, - query: signal_status_query, - }), -]); - -export type SetSignalsStatusSchema = t.TypeOf; -export type SetSignalsStatusSchemaDecoded = SetSignalsStatusSchema; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_type_dependents.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_type_dependents.test.ts deleted file mode 100644 index 97cf74435c2947..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_type_dependents.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { setSignalStatusValidateTypeDependents } from './set_signal_status_type_dependents'; -import type { SetSignalsStatusSchema } from './set_signal_status_route'; - -describe('update_rules_type_dependents', () => { - test('You can have just a "signals_id"', () => { - const schema: SetSignalsStatusSchema = { - status: 'open', - signal_ids: ['some-id'], - }; - const errors = setSignalStatusValidateTypeDependents(schema); - expect(errors).toEqual([]); - }); - - test('You can have just a "query"', () => { - const schema: SetSignalsStatusSchema = { - status: 'open', - query: {}, - }; - const errors = setSignalStatusValidateTypeDependents(schema); - expect(errors).toEqual([]); - }); - - test('You cannot have both a "signals_id" and a "query"', () => { - const schema: SetSignalsStatusSchema = { - status: 'open', - query: {}, - signal_ids: ['some-id'], - }; - const errors = setSignalStatusValidateTypeDependents(schema); - expect(errors).toEqual(['both "signal_ids" and "query" cannot exist, choose one or the other']); - }); - - test('You must set either an "signals_id" and a "query"', () => { - const schema: SetSignalsStatusSchema = { - status: 'open', - }; - const errors = setSignalStatusValidateTypeDependents(schema); - expect(errors).toEqual(['either "signal_ids" or "query" must be set']); - }); -}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_type_dependents.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_type_dependents.ts deleted file mode 100644 index a484fde33d107c..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signal_status_type_dependents.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { SetSignalsStatusSchema } from './set_signal_status_route'; - -export const validateId = (signalStatus: SetSignalsStatusSchema): string[] => { - if (signalStatus.signal_ids != null && signalStatus.query != null) { - return ['both "signal_ids" and "query" cannot exist, choose one or the other']; - } else if (signalStatus.signal_ids == null && signalStatus.query == null) { - return ['either "signal_ids" or "query" must be set']; - } else { - return []; - } -}; - -export const setSignalStatusValidateTypeDependents = (schema: SetSignalsStatusSchema): string[] => { - return [...validateId(schema)]; -}; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.gen.ts new file mode 100644 index 00000000000000..a64a35d16d83e3 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.gen.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Set alerts status API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { NonEmptyString } from '../../../model/primitives.gen'; +import { AlertStatus } from '../../../model/alert.gen'; + +export type SetAlertsStatusByIds = z.infer; +export const SetAlertsStatusByIds = z.object({ + signal_ids: z.array(NonEmptyString).min(1), + status: AlertStatus, +}); + +export type SetAlertsStatusByQuery = z.infer; +export const SetAlertsStatusByQuery = z.object({ + query: z.object({}).catchall(z.unknown()), + status: AlertStatus, + conflicts: z.enum(['abort', 'proceed']).optional().default('abort'), +}); + +export type SetAlertsStatusRequestBody = z.infer; +export const SetAlertsStatusRequestBody = z.union([SetAlertsStatusByIds, SetAlertsStatusByQuery]); +export type SetAlertsStatusRequestBodyInput = z.input; + +/** + * Elasticsearch update by query response + */ +export type SetAlertsStatusResponse = z.infer; +export const SetAlertsStatusResponse = z.object({}).catchall(z.unknown()); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.schema.yaml new file mode 100644 index 00000000000000..29ee065c77e6b5 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.schema.yaml @@ -0,0 +1,81 @@ +openapi: 3.0.0 +info: + title: Set alerts status API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/status: + post: + x-labels: [serverless, ess] + operationId: SetAlertsStatus + x-codegen-enabled: true + summary: Sets the status of one or more alerts + tags: + - Alerts API + requestBody: + description: An object containing desired status and explicit alert ids or a query to select alerts + required: true + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/SetAlertsStatusByIds' + - $ref: '#/components/schemas/SetAlertsStatusByQuery' + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + additionalProperties: true + description: Elasticsearch update by query response + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + SetAlertsStatusByIds: + type: object + properties: + signal_ids: + type: array + items: + $ref: '../../../model/primitives.schema.yaml#/components/schemas/NonEmptyString' + minItems: 1 + status: + $ref: '../../../model/alert.schema.yaml#/components/schemas/AlertStatus' + required: [signal_ids, status] + + SetAlertsStatusByQuery: + type: object + properties: + query: + type: object + additionalProperties: true + status: + $ref: '../../../model/alert.schema.yaml#/components/schemas/AlertStatus' + conflicts: + type: string + enum: + - abort + - proceed + default: abort + required: [query, status] diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.gen.ts new file mode 100644 index 00000000000000..f82dedc27a289e --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.gen.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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Initiates alerts migration API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { NonEmptyString } from '../../../model/primitives.gen'; + +export type AlertsReindexOptions = z.infer; +export const AlertsReindexOptions = z.object({ + requests_per_second: z.number().int().min(1).optional(), + size: z.number().int().min(1).optional(), + slices: z.number().int().min(1).optional(), +}); + +export type AlertsIndexMigrationSuccess = z.infer; +export const AlertsIndexMigrationSuccess = z.object({ + index: z.string(), + migration_id: z.string(), + migration_index: z.string(), +}); + +export type AlertsIndexMigrationError = z.infer; +export const AlertsIndexMigrationError = z.object({ + index: z.string(), + error: z.object({ + message: z.string(), + status_code: z.string(), + }), +}); + +export type SkippedAlertsIndexMigration = z.infer; +export const SkippedAlertsIndexMigration = z.object({ + index: z.string(), +}); + +export type CreateAlertsMigrationRequestBody = z.infer; +export const CreateAlertsMigrationRequestBody = z + .object({ + index: z.array(NonEmptyString).min(1), + }) + .merge(AlertsReindexOptions); +export type CreateAlertsMigrationRequestBodyInput = z.input< + typeof CreateAlertsMigrationRequestBody +>; + +export type CreateAlertsMigrationResponse = z.infer; +export const CreateAlertsMigrationResponse = z.object({ + indices: z.array( + z.union([AlertsIndexMigrationSuccess, AlertsIndexMigrationError, SkippedAlertsIndexMigration]) + ), +}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.schema.yaml new file mode 100644 index 00000000000000..26204ea0d61954 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.schema.yaml @@ -0,0 +1,120 @@ +openapi: 3.0.0 +info: + title: Initiates alerts migration API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/migration: + post: + x-labels: [ess] + operationId: CreateAlertsMigration + x-codegen-enabled: true + summary: Initiates an alerts migration + tags: + - Alerts migration API + requestBody: + description: Alerts migration parameters + required: true + content: + application/json: + schema: + allOf: + - type: object + properties: + index: + type: array + items: + $ref: '../../../model/primitives.schema.yaml#/components/schemas/NonEmptyString' + minItems: 1 + required: [index] + - $ref: '#/components/schemas/AlertsReindexOptions' + + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + indices: + type: array + items: + oneOf: + - $ref: '#/components/schemas/AlertsIndexMigrationSuccess' + - $ref: '#/components/schemas/AlertsIndexMigrationError' + - $ref: '#/components/schemas/SkippedAlertsIndexMigration' + required: [indices] + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + AlertsReindexOptions: + type: object + properties: + requests_per_second: + type: integer + minimum: 1 + size: + type: integer + minimum: 1 + slices: + type: integer + minimum: 1 + + AlertsIndexMigrationSuccess: + type: object + properties: + index: + type: string + migration_id: + type: string + migration_index: + type: string + required: + - index + - migration_id + - migration_index + + AlertsIndexMigrationError: + type: object + properties: + index: + type: string + error: + type: object + properties: + message: + type: string + status_code: + type: string + required: [message, status_code] + required: + - index + - error + + SkippedAlertsIndexMigration: + type: object + properties: + index: + type: string + required: + - index diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.mock.ts index ccb5543ef72d2e..09a94fc86224c0 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.mock.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.mock.ts @@ -5,10 +5,10 @@ * 2.0. */ -import type { CreateSignalsMigrationSchema } from './create_signals_migration_route'; +import type { CreateAlertsMigrationRequestBody } from './create_signals_migration.gen'; export const getCreateSignalsMigrationSchemaMock = ( index: string = 'signals-index' -): CreateSignalsMigrationSchema => ({ +): CreateAlertsMigrationRequestBody => ({ index: [index], }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts deleted file mode 100644 index 9089efeb87d050..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts +++ /dev/null @@ -1,29 +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 * as t from 'io-ts'; - -import { PositiveInteger, PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; - -export const signalsReindexOptions = t.partial({ - requests_per_second: t.number, - size: PositiveIntegerGreaterThanZero, - slices: PositiveInteger, -}); - -export type SignalsReindexOptions = t.TypeOf; - -export const createSignalsMigrationSchema = t.intersection([ - t.exact( - t.type({ - index: t.array(t.string), - }) - ), - t.exact(signalsReindexOptions), -]); - -export type CreateSignalsMigrationSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.gen.ts new file mode 100644 index 00000000000000..c82407052c972e --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.gen.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Alerts migration cleanup API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +export type MigrationCleanupResult = z.infer; +export const MigrationCleanupResult = z.object({ + id: z.string(), + destinationIndex: z.string(), + status: z.enum(['success', 'failure', 'pending']), + sourceIndex: z.string(), + version: z.string(), + updated: z.string().datetime(), + error: z + .object({ + message: z.string(), + status_code: z.number().int(), + }) + .optional(), +}); + +export type AlertsMigrationCleanupRequestBody = z.infer; +export const AlertsMigrationCleanupRequestBody = z.object({ + migration_ids: z.array(z.string()).min(1), +}); +export type AlertsMigrationCleanupRequestBodyInput = z.input< + typeof AlertsMigrationCleanupRequestBody +>; + +export type AlertsMigrationCleanupResponse = z.infer; +export const AlertsMigrationCleanupResponse = z.array(MigrationCleanupResult); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.schema.yaml new file mode 100644 index 00000000000000..7b8136f3702cff --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.schema.yaml @@ -0,0 +1,100 @@ +openapi: 3.0.0 +info: + title: Alerts migration cleanup API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/migration: + delete: + x-labels: [ess] + operationId: AlertsMigrationCleanup + x-codegen-enabled: true + summary: Performs alerts migration(s) cleanup + description: | + Migrations favor data integrity over shard size. Consequently, unused or orphaned indices are artifacts of + the migration process. A successful migration will result in both the old and new indices being present. + As such, the old, orphaned index can (and likely should) be deleted. While you can delete these indices manually, + the endpoint accomplishes this task by applying a deletion policy to the relevant index, causing it to be deleted + after 30 days. It also deletes other artifacts specific to the migration implementation. + tags: + - Alerts migration API + requestBody: + description: Array of `migration_id`s to cleanup + required: true + content: + application/json: + schema: + type: object + properties: + migration_ids: + type: array + items: + type: string + minItems: 1 + required: [migration_ids] + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/MigrationCleanupResult' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + MigrationCleanupResult: + type: object + properties: + id: + type: string + destinationIndex: + type: string + status: + type: string + enum: + - success + - failure + - pending + sourceIndex: + type: string + version: + type: string + updated: + type: string + format: date-time + error: + type: object + properties: + message: + type: string + status_code: + type: integer + required: [message, status_code] + required: + - id + - destinationIndex + - status + - sourceIndex + - version + - updated diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration_route.ts deleted file mode 100644 index 837f34f3ec14f4..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration_route.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; - -export const deleteSignalsMigrationSchema = t.exact( - t.type({ - migration_ids: t.array(t.string), - }) -); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.gen.ts new file mode 100644 index 00000000000000..cd18cad8e1cfab --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.gen.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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Finalize alerts migration API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +export type MigrationFinalizationResult = z.infer; +export const MigrationFinalizationResult = z.object({ + id: z.string(), + completed: z.boolean(), + destinationIndex: z.string(), + status: z.enum(['success', 'failure', 'pending']), + sourceIndex: z.string(), + version: z.string(), + updated: z.string().datetime(), + error: z + .object({ + message: z.string(), + status_code: z.number().int(), + }) + .optional(), +}); + +export type FinalizeAlertsMigrationRequestBody = z.infer; +export const FinalizeAlertsMigrationRequestBody = z.object({ + migration_ids: z.array(z.string()).min(1), +}); +export type FinalizeAlertsMigrationRequestBodyInput = z.input< + typeof FinalizeAlertsMigrationRequestBody +>; + +export type FinalizeAlertsMigrationResponse = z.infer; +export const FinalizeAlertsMigrationResponse = z.array(MigrationFinalizationResult); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.schema.yaml new file mode 100644 index 00000000000000..3654973f9de7ea --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.schema.yaml @@ -0,0 +1,101 @@ +openapi: 3.0.0 +info: + title: Finalize alerts migration API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/finalize_migration: + post: + x-labels: [ess] + operationId: FinalizeAlertsMigration + x-codegen-enabled: true + summary: Finalizes alerts migration(s) + description: | + The finalization endpoint replaces the original index's alias with the successfully migrated index's alias. + The endpoint is idempotent; therefore, it can safely be used to poll a given migration and, upon completion, + finalize it. + tags: + - Alerts migration API + requestBody: + description: Array of `migration_id`s to finalize + required: true + content: + application/json: + schema: + type: object + properties: + migration_ids: + type: array + items: + type: string + minItems: 1 + required: [migration_ids] + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/MigrationFinalizationResult' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + MigrationFinalizationResult: + type: object + properties: + id: + type: string + completed: + type: boolean + destinationIndex: + type: string + status: + type: string + enum: + - success + - failure + - pending + sourceIndex: + type: string + version: + type: string + updated: + type: string + format: date-time + error: + type: object + properties: + message: + type: string + status_code: + type: integer + required: [message, status_code] + required: + - id + - completed + - destinationIndex + - status + - sourceIndex + - version + - updated diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration_route.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration_route.mock.ts index 25d66c5b68d094..b43a04819e67f3 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration_route.mock.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration_route.mock.ts @@ -5,8 +5,8 @@ * 2.0. */ -import type { FinalizeSignalsMigrationSchema } from './finalize_signals_migration_route'; +import type { FinalizeAlertsMigrationRequestBody } from './finalize_signals_migration.gen'; -export const getFinalizeSignalsMigrationSchemaMock = (): FinalizeSignalsMigrationSchema => ({ +export const getFinalizeSignalsMigrationSchemaMock = (): FinalizeAlertsMigrationRequestBody => ({ migration_ids: ['migrationSOIdentifier'], }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration_route.ts deleted file mode 100644 index a4a48a7bc0c21b..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration_route.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; - -export const finalizeSignalsMigrationSchema = t.exact( - t.type({ - migration_ids: t.array(t.string), - }) -); - -export type FinalizeSignalsMigrationSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.gen.ts new file mode 100644 index 00000000000000..acf9c9edd389d3 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.gen.ts @@ -0,0 +1,61 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Get alerts migration status API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; +import { isValidDateMath } from '@kbn/zod-helpers'; + +import { NonEmptyString } from '../../../model/primitives.gen'; + +export type AlertVersion = z.infer; +export const AlertVersion = z.object({ + version: z.number().int(), + count: z.number().int(), +}); + +export type MigrationStatus = z.infer; +export const MigrationStatus = z.object({ + id: NonEmptyString, + status: z.enum(['success', 'failure', 'pending']), + version: z.number().int(), + updated: z.string().datetime(), +}); + +export type IndexMigrationStatus = z.infer; +export const IndexMigrationStatus = z.object({ + index: NonEmptyString, + version: z.number().int(), + signal_versions: z.array(AlertVersion), + migrations: z.array(MigrationStatus), + is_outdated: z.boolean(), +}); + +export type GetAlertsMigrationStatusRequestQuery = z.infer< + typeof GetAlertsMigrationStatusRequestQuery +>; +export const GetAlertsMigrationStatusRequestQuery = z.object({ + /** + * Maximum age of qualifying detection alerts + */ + from: z.string().superRefine(isValidDateMath), +}); +export type GetAlertsMigrationStatusRequestQueryInput = z.input< + typeof GetAlertsMigrationStatusRequestQuery +>; + +export type GetAlertsMigrationStatusResponse = z.infer; +export const GetAlertsMigrationStatusResponse = z.object({ + indices: z.array(IndexMigrationStatus), +}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.schema.yaml new file mode 100644 index 00000000000000..b480b4374498b9 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.schema.yaml @@ -0,0 +1,114 @@ +openapi: 3.0.0 +info: + title: Get alerts migration status API endpoint + version: '2023-10-31' +paths: + /api/detection_engine/signals/migration_status: + post: + x-labels: [ess] + operationId: GetAlertsMigrationStatus + x-codegen-enabled: true + summary: Returns an alerts migration status + tags: + - Alerts migration API + parameters: + - name: from + in: query + description: Maximum age of qualifying detection alerts + required: true + schema: + type: string + description: | + Time from which data is analyzed. For example, now-4200s means the rule analyzes data from 70 minutes + before its start time. Defaults to now-6m (analyzes data from 6 minutes before the start time). + format: date-math + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + indices: + type: array + items: + $ref: '#/components/schemas/IndexMigrationStatus' + required: [indices] + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + AlertVersion: + type: object + properties: + version: + type: integer + count: + type: integer + required: [version, count] + + MigrationStatus: + type: object + properties: + id: + $ref: '../../../model/primitives.schema.yaml#/components/schemas/NonEmptyString' + status: + type: string + enum: + - success + - failure + - pending + version: + type: integer + updated: + type: string + format: date-time + required: + - id + - status + - version + - updated + + IndexMigrationStatus: + type: object + properties: + index: + $ref: '../../../model/primitives.schema.yaml#/components/schemas/NonEmptyString' + version: + type: integer + signal_versions: + type: array + items: + $ref: '#/components/schemas/AlertVersion' + migrations: + type: array + items: + $ref: '#/components/schemas/MigrationStatus' + is_outdated: + type: boolean + required: + - index + - version + - signal_versions + - migrations + - is_outdated diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status_route.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status_route.mock.ts index 8cc78ffa9700e0..968d72d6f40d07 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status_route.mock.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status_route.mock.ts @@ -5,8 +5,8 @@ * 2.0. */ -import type { GetSignalsMigrationStatusSchema } from './get_signals_migration_status_route'; +import type { GetAlertsMigrationStatusRequestQuery } from './get_signals_migration_status.gen'; -export const getSignalsMigrationStatusSchemaMock = (): GetSignalsMigrationStatusSchema => ({ +export const getSignalsMigrationStatusSchemaMock = (): GetAlertsMigrationStatusRequestQuery => ({ from: 'now-30d', }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status_route.ts deleted file mode 100644 index f2a9fc210df2bf..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status_route.ts +++ /dev/null @@ -1,18 +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 * as t from 'io-ts'; - -import { RuleIntervalFrom } from '@kbn/securitysolution-io-ts-alerting-types'; - -export const getSignalsMigrationStatusSchema = t.exact( - t.type({ - from: RuleIntervalFrom, - }) -); - -export type GetSignalsMigrationStatusSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/index.ts index 78452dc62f46c1..84b00fc9f297c7 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -export * from './create_signals_migration/create_signals_migration_route'; -export * from './delete_signals_migration/delete_signals_migration_route'; -export * from './finalize_signals_migration/finalize_signals_migration_route'; -export * from './get_signals_migration_status/get_signals_migration_status_route'; +export * from './create_signals_migration/create_signals_migration.gen'; +export * from './delete_signals_migration/delete_signals_migration.gen'; +export * from './finalize_signals_migration/finalize_signals_migration.gen'; +export * from './get_signals_migration_status/get_signals_migration_status.gen'; diff --git a/x-pack/plugins/security_solution/common/api/model/alert.gen.ts b/x-pack/plugins/security_solution/common/api/model/alert.gen.ts index 19ebcf2dee7342..d149d36ab64b80 100644 --- a/x-pack/plugins/security_solution/common/api/model/alert.gen.ts +++ b/x-pack/plugins/security_solution/common/api/model/alert.gen.ts @@ -23,3 +23,14 @@ import { NonEmptyString } from './primitives.gen'; */ export type AlertIds = z.infer; export const AlertIds = z.array(NonEmptyString).min(1); + +export type AlertTag = z.infer; +export const AlertTag = NonEmptyString; + +export type AlertTags = z.infer; +export const AlertTags = z.array(AlertTag); + +export type AlertStatus = z.infer; +export const AlertStatus = z.enum(['open', 'closed', 'acknowledged', 'in-progress']); +export type AlertStatusEnum = typeof AlertStatus.enum; +export const AlertStatusEnum = AlertStatus.enum; diff --git a/x-pack/plugins/security_solution/common/api/model/alert.schema.yaml b/x-pack/plugins/security_solution/common/api/model/alert.schema.yaml index f28508dc620f2d..ecf7e02d6ebe3d 100644 --- a/x-pack/plugins/security_solution/common/api/model/alert.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/model/alert.schema.yaml @@ -12,3 +12,19 @@ components: $ref: './primitives.schema.yaml#/components/schemas/NonEmptyString' minItems: 1 description: A list of alerts ids. + + AlertTag: + $ref: './primitives.schema.yaml#/components/schemas/NonEmptyString' + + AlertTags: + type: array + items: + $ref: '#/components/schemas/AlertTag' + + AlertStatus: + type: string + enum: + - open + - closed + - acknowledged + - in-progress diff --git a/x-pack/plugins/security_solution/common/api/model/error_responses.gen.ts b/x-pack/plugins/security_solution/common/api/model/error_responses.gen.ts new file mode 100644 index 00000000000000..17d2c59bd338fc --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/model/error_responses.gen.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Error Schema + * version: not applicable + */ + +import { z } from 'zod'; + +export type PlatformErrorResponse = z.infer; +export const PlatformErrorResponse = z.object({ + statusCode: z.number().int(), + error: z.string(), + message: z.string(), +}); + +export type SiemErrorResponse = z.infer; +export const SiemErrorResponse = z.object({ + status_code: z.number().int(), + message: z.string(), +}); diff --git a/x-pack/plugins/security_solution/common/api/model/error_responses.schema.yaml b/x-pack/plugins/security_solution/common/api/model/error_responses.schema.yaml new file mode 100644 index 00000000000000..8f0891f3f574fc --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/model/error_responses.schema.yaml @@ -0,0 +1,32 @@ +openapi: 3.0.0 +info: + title: Error Schema + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + PlatformErrorResponse: + type: object + properties: + statusCode: + type: integer + error: + type: string + message: + type: string + required: + - statusCode + - error + - message + + SiemErrorResponse: + type: object + properties: + status_code: + type: integer + message: + type: string + required: + - status_code + - message diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration.ts index da49cda43507af..8bc38b1ecdf945 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration.ts @@ -6,7 +6,7 @@ */ import type { ElasticsearchClient } from '@kbn/core/server'; -import type { SignalsReindexOptions } from '../../../../common/api/detection_engine/signals_migration'; +import type { AlertsReindexOptions } from '../../../../common/api/detection_engine/signals_migration'; import { createMigrationIndex } from './create_migration_index'; export interface CreatedMigration { @@ -24,7 +24,7 @@ export interface CreatedMigration { * @param esClient An {@link ElasticsearchClient} * @param index name of the concrete signals index to be migrated * @param version version of the current signals template/mappings - * @param reindexOptions object containing reindex options {@link SignalsReindexOptions} + * @param reindexOptions object containing reindex options {@link AlertsReindexOptions} * * @returns identifying information representing the {@link MigrationInfo} * @throws if elasticsearch returns an error @@ -37,7 +37,7 @@ export const createMigration = async ({ }: { esClient: ElasticsearchClient; index: string; - reindexOptions: SignalsReindexOptions; + reindexOptions: AlertsReindexOptions; version: number; }): Promise => { const migrationIndex = await createMigrationIndex({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/migration_service.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/migration_service.ts index e0c82f70549fd0..5a4399bd6389c3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/migration_service.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/migration_service.ts @@ -6,7 +6,7 @@ */ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; -import type { SignalsReindexOptions } from '../../../../common/api/detection_engine/signals_migration'; +import type { AlertsReindexOptions } from '../../../../common/api/detection_engine/signals_migration'; import type { SignalsMigrationSO } from './saved_objects_schema'; import { createMigrationSavedObject } from './create_migration_saved_object'; import { createMigration } from './create_migration'; @@ -16,7 +16,7 @@ import { deleteMigration } from './delete_migration'; export interface CreateParams { index: string; version: number; - reindexOptions: SignalsReindexOptions; + reindexOptions: AlertsReindexOptions; } export interface FinalizeParams { 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 82a40cbf71a417..2bd7efdbbdcf2e 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 @@ -11,6 +11,12 @@ import { ALERT_WORKFLOW_STATUS } from '@kbn/rule-data-utils'; import { ruleTypeMappings } from '@kbn/securitysolution-rules'; import type { SanitizedRule, ResolvedSanitizedRule } from '@kbn/alerting-plugin/common'; +import type { + SetAlertsStatusByIds, + SetAlertsStatusByQuery, + SetAlertsStatusRequestBodyInput, + SearchAlertsRequestBody, +} from '../../../../../common/api/detection_engine/signals'; import { DETECTION_ENGINE_RULES_URL, DETECTION_ENGINE_SIGNALS_STATUS_URL, @@ -36,10 +42,7 @@ import { } from '../../../../../common/api/detection_engine/rule_management/mocks'; import { getCreateRulesSchemaMock } from '../../../../../common/api/detection_engine/model/rule_schema/mocks'; -import type { - QuerySignalsSchemaDecoded, - SetSignalsStatusSchemaDecoded, -} from '../../../../../common/api/detection_engine/signals'; + import { getFinalizeSignalsMigrationSchemaMock, getSignalsMigrationStatusSchemaMock, @@ -53,26 +56,28 @@ import { getQueryRuleParams } from '../../rule_schema/mocks'; import { requestMock } from './request'; import type { HapiReadableStream } from '../../../../types'; -export const typicalSetStatusSignalByIdsPayload = (): SetSignalsStatusSchemaDecoded => ({ +export const typicalSetStatusSignalByIdsPayload = (): SetAlertsStatusByIds => ({ signal_ids: ['somefakeid1', 'somefakeid2'], status: 'closed', }); -export const typicalSetStatusSignalByQueryPayload = (): SetSignalsStatusSchemaDecoded => ({ +export const typicalSetStatusSignalByQueryPayload = (): SetAlertsStatusByQuery => ({ query: { bool: { filter: { range: { '@timestamp': { gte: 'now-2M', lte: 'now/M' } } } } }, status: 'closed', + conflicts: 'abort', }); -export const typicalSignalsQuery = (): QuerySignalsSchemaDecoded => ({ +export const typicalSignalsQuery = (): SearchAlertsRequestBody => ({ aggs: {}, query: { match_all: {} }, }); -export const typicalSignalsQueryAggs = (): QuerySignalsSchemaDecoded => ({ +export const typicalSignalsQueryAggs = (): SearchAlertsRequestBody => ({ aggs: { statuses: { terms: { field: ALERT_WORKFLOW_STATUS, size: 10 } } }, }); -export const setStatusSignalMissingIdsAndQueryPayload = (): SetSignalsStatusSchemaDecoded => ({ +// @ts-expect-error data with missing required fields +export const setStatusSignalMissingIdsAndQueryPayload = (): SetAlertsStatusRequestBodyInput => ({ status: 'closed', }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.test.ts index e48cd6ff2dab10..5d81134325c503 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.test.ts @@ -7,7 +7,6 @@ import { requestMock, serverMock } from '../__mocks__'; import type { SetupPlugins } from '../../../../plugin'; -import type { SignalsReindexOptions } from '../../../../../common/api/detection_engine/signals_migration'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_URL } from '../../../../../common/constants'; import { getCreateSignalsMigrationSchemaMock } from '../../../../../common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.mock'; import { getIndexVersionsByIndex } from '../../migrations/get_index_versions_by_index'; @@ -17,6 +16,7 @@ import { getIndexAliases } from '@kbn/securitysolution-es-utils'; import { getTemplateVersion } from '../index/check_template_version'; import { createSignalsMigrationRoute } from './create_signals_migration_route'; import { SIGNALS_TEMPLATE_VERSION } from '../index/get_signals_template'; +import type { AlertsReindexOptions } from '../../../../../common/api/detection_engine/signals_migration'; jest.mock('../index/check_template_version'); jest.mock('@kbn/securitysolution-es-utils', () => { @@ -53,7 +53,7 @@ describe('creating signals migrations route', () => { }); it('passes options to the createMigration', async () => { - const reindexOptions: SignalsReindexOptions = { requests_per_second: 4, size: 10, slices: 2 }; + const reindexOptions: AlertsReindexOptions = { requests_per_second: 4, size: 10, slices: 2 }; const request = requestMock.create({ method: 'post', path: DETECTION_ENGINE_SIGNALS_MIGRATION_URL, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts index 198a1992058fac..51e1843e9b8e8c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts @@ -6,11 +6,11 @@ */ import { transformError, BadRequestError, getIndexAliases } from '@kbn/securitysolution-es-utils'; +import { CreateAlertsMigrationRequestBody } from '../../../../../common/api/detection_engine/signals_migration'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import type { SetupPlugins } from '../../../../plugin'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_URL } from '../../../../../common/constants'; -import { createSignalsMigrationSchema } from '../../../../../common/api/detection_engine/signals_migration'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../utils'; import { getTemplateVersion } from '../index/check_template_version'; @@ -35,7 +35,9 @@ export const createSignalsMigrationRoute = ( .addVersion( { version: '2023-10-31', - validate: { request: { body: buildRouteValidation(createSignalsMigrationSchema) } }, + validate: { + request: { body: buildRouteValidationWithZod(CreateAlertsMigrationRequestBody) }, + }, }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts index 4a4a38e074c0b3..c2e364e58ca5be 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts @@ -6,11 +6,11 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { AlertsMigrationCleanupRequestBody } from '../../../../../common/api/detection_engine/signals_migration'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import type { SetupPlugins } from '../../../../plugin'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_URL } from '../../../../../common/constants'; -import { deleteSignalsMigrationSchema } from '../../../../../common/api/detection_engine/signals_migration'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../utils'; import { signalsMigrationService } from '../../migrations/migration_service'; @@ -31,7 +31,9 @@ export const deleteSignalsMigrationRoute = ( .addVersion( { version: '2023-10-31', - validate: { request: { body: buildRouteValidation(deleteSignalsMigrationSchema) } }, + validate: { + request: { body: buildRouteValidationWithZod(AlertsMigrationCleanupRequestBody) }, + }, }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts index 12d6520fa52d15..bfec0f82867a6e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts @@ -7,11 +7,11 @@ import { transformError, BadRequestError } from '@kbn/securitysolution-es-utils'; import type { RuleDataPluginService } from '@kbn/rule-registry-plugin/server'; +import { FinalizeAlertsMigrationRequestBody } from '../../../../../common/api/detection_engine/signals_migration'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import type { SetupPlugins } from '../../../../plugin'; import { DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL } from '../../../../../common/constants'; -import { finalizeSignalsMigrationSchema } from '../../../../../common/api/detection_engine/signals_migration'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { isMigrationFailed, isMigrationPending } from '../../migrations/helpers'; import { signalsMigrationService } from '../../migrations/migration_service'; import { buildSiemResponse } from '../utils'; @@ -34,7 +34,9 @@ export const finalizeSignalsMigrationRoute = ( .addVersion( { version: '2023-10-31', - validate: { request: { body: buildRouteValidation(finalizeSignalsMigrationSchema) } }, + validate: { + request: { body: buildRouteValidationWithZod(FinalizeAlertsMigrationRequestBody) }, + }, }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/get_signals_migration_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/get_signals_migration_status_route.ts index dbf6d97d4b72b0..185e0c6ed61758 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/get_signals_migration_status_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/get_signals_migration_status_route.ts @@ -6,10 +6,10 @@ */ import { transformError, getIndexAliases } from '@kbn/securitysolution-es-utils'; +import { GetAlertsMigrationStatusRequestQuery } from '../../../../../common/api/detection_engine/signals_migration'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL } from '../../../../../common/constants'; -import { getSignalsMigrationStatusSchema } from '../../../../../common/api/detection_engine/signals_migration'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { getIndexVersionsByIndex } from '../../migrations/get_index_versions_by_index'; import { getMigrationSavedObjectsByIndex } from '../../migrations/get_migration_saved_objects_by_index'; import { getSignalsIndicesInRange } from '../../migrations/get_signals_indices_in_range'; @@ -30,7 +30,9 @@ export const getSignalsMigrationStatusRoute = (router: SecuritySolutionPluginRou .addVersion( { version: '2023-10-31', - validate: { request: { query: buildRouteValidation(getSignalsMigrationStatusSchema) } }, + validate: { + request: { query: buildRouteValidationWithZod(GetAlertsMigrationStatusRequestQuery) }, + }, }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals.test.ts index ece3b64ad2fbf3..1b2bdb6ca1ef4e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals.test.ts @@ -150,12 +150,10 @@ describe('set signal status', () => { path: DETECTION_ENGINE_SIGNALS_STATUS_URL, body: setStatusSignalMissingIdsAndQueryPayload(), }); - const response = await server.inject(request, requestContextMock.convertContext(context)); - expect(response.status).toEqual(400); - expect(response.body).toEqual({ - message: ['either "signal_ids" or "query" must be set'], - status_code: 400, - }); + + const result = server.validate(request); + + expect(result.badRequest).toHaveBeenCalled(); }); test('rejects if signal_ids but no status', async () => { @@ -167,9 +165,7 @@ describe('set signal status', () => { }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "undefined" supplied to "status"' - ); + expect(result.badRequest).toHaveBeenCalled(); }); test('rejects if query but no status', async () => { @@ -181,9 +177,7 @@ describe('set signal status', () => { }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "undefined" supplied to "status"' - ); + expect(result.badRequest).toHaveBeenCalled(); }); test('rejects if query and signal_ids but no status', async () => { @@ -199,9 +193,7 @@ describe('set signal status', () => { }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "undefined" supplied to "status"' - ); + expect(result.badRequest).toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts index 43a1951bea4c5d..3030e5fe799b6a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts @@ -14,11 +14,8 @@ import { } from '@kbn/rule-data-utils'; import type { ElasticsearchClient, Logger, StartServicesAccessor } from '@kbn/core/server'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; -import { - setSignalStatusValidateTypeDependents, - setSignalsStatusSchema, -} from '../../../../../common/api/detection_engine/signals'; -import type { SetSignalsStatusSchemaDecoded } from '../../../../../common/api/detection_engine/signals'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; +import { SetAlertsStatusRequestBody } from '../../../../../common/api/detection_engine/signals'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DEFAULT_ALERTS_INDEX, @@ -28,7 +25,6 @@ import { buildSiemResponse } from '../utils'; import type { ITelemetryEventsSender } from '../../../telemetry/sender'; import { INSIGHTS_CHANNEL } from '../../../telemetry/constants'; import type { StartPlugins } from '../../../../plugin'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import { getSessionIDfromKibanaRequest, createAlertStatusPayloads, @@ -53,27 +49,19 @@ export const setSignalsStatusRoute = ( version: '2023-10-31', validate: { request: { - body: buildRouteValidation< - typeof setSignalsStatusSchema, - SetSignalsStatusSchemaDecoded - >(setSignalsStatusSchema), + body: buildRouteValidationWithZod(SetAlertsStatusRequestBody), }, }, }, async (context, request, response) => { - const { conflicts, signal_ids: signalIds, query, status } = request.body; + const { status } = request.body; const core = await context.core; const securitySolution = await context.securitySolution; const esClient = core.elasticsearch.client.asCurrentUser; const siemClient = securitySolution?.getAppClient(); const siemResponse = buildSiemResponse(response); - const validationErrors = setSignalStatusValidateTypeDependents(request.body); const spaceId = securitySolution?.getSpaceId() ?? 'default'; - if (validationErrors.length) { - return siemResponse.error({ statusCode: 400, body: validationErrors }); - } - if (!siemClient) { return siemResponse.error({ statusCode: 404 }); } @@ -85,9 +73,13 @@ export const setSignalsStatusRoute = ( sender.isTelemetryOptedIn(), security?.authc.getCurrentUser(request)?.username, ]); + if (isTelemetryOptedIn && clusterId) { // Sometimes the ids are in the query not passed in the request? - const toSendAlertIds = get(query, 'bool.filter.terms._id') || signalIds; + const toSendAlertIds = + 'signal_ids' in request.body + ? request.body.signal_ids + : (get(request.body.query, 'bool.filter.terms._id') as string[]); // Get Context for Insights Payloads const sessionId = getSessionIDfromKibanaRequest(clusterId, request); if (username && toSendAlertIds && sessionId && status) { @@ -105,10 +97,15 @@ export const setSignalsStatusRoute = ( } try { - if (signalIds) { + if ('signal_ids' in request.body) { + const { signal_ids: signalIds } = request.body; + const body = await updateSignalsStatusByIds(status, signalIds, spaceId, esClient, user); + return response.ok({ body }); } else { + const { conflicts, query } = request.body; + const body = await updateSignalsStatusByQuery( status, query, @@ -117,6 +114,7 @@ export const setSignalsStatusRoute = ( esClient, user ); + return response.ok({ body }); } } catch (err) { @@ -132,7 +130,7 @@ export const setSignalsStatusRoute = ( }; const updateSignalsStatusByIds = async ( - status: SetSignalsStatusSchemaDecoded['status'], + status: SetAlertsStatusRequestBody['status'], signalsId: string[], spaceId: string, esClient: ElasticsearchClient, @@ -158,7 +156,7 @@ const updateSignalsStatusByIds = async ( * This method calls `updateByQuery` with `refresh: true` which is expensive on serverless. */ const updateSignalsStatusByQuery = async ( - status: SetSignalsStatusSchemaDecoded['status'], + status: SetAlertsStatusRequestBody['status'], query: object | undefined, options: { conflicts: 'abort' | 'proceed' }, spaceId: string, @@ -181,7 +179,7 @@ const updateSignalsStatusByQuery = async ( }); const getUpdateSignalStatusScript = ( - status: SetSignalsStatusSchemaDecoded['status'], + status: SetAlertsStatusRequestBody['status'], user: AuthenticatedUser | null ) => ({ source: `if (ctx._source['${ALERT_WORKFLOW_STATUS}'] != null && ctx._source['${ALERT_WORKFLOW_STATUS}'] != '${status}') { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts index 3bd52ebdaacdae..e868c2b9790182 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -8,13 +8,12 @@ import type { MappingRuntimeFields, Sort } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { transformError } from '@kbn/securitysolution-es-utils'; import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; +import type { AggregationsAggregationContainer } from '@elastic/elasticsearch/lib/api/types'; +import { SearchAlertsRequestBody } from '../../../../../common/api/detection_engine/signals'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; - -import type { QuerySignalsSchemaDecoded } from '../../../../../common/api/detection_engine/signals'; -import { querySignalsSchema } from '../../../../../common/api/detection_engine/signals'; export const querySignalsRoute = ( router: SecuritySolutionPluginRouter, @@ -33,9 +32,7 @@ export const querySignalsRoute = ( version: '2023-10-31', validate: { request: { - body: buildRouteValidation( - querySignalsSchema - ), + body: buildRouteValidationWithZod(SearchAlertsRequestBody), }, }, }, @@ -67,8 +64,7 @@ export const querySignalsRoute = ( index: indexPattern, body: { query, - // Note: I use a spread operator to please TypeScript with aggs: { ...aggs } - aggs: { ...aggs }, + aggs: aggs as Record, _source, fields, track_total_hits, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.test.ts index ab9d79c53fc3f8..eaeae10d264719 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.test.ts @@ -75,20 +75,9 @@ describe('setAlertTagsRoute', () => { body: getSetAlertTagsRequestMock(['tag-1'], ['tag-2']), }); - context.core.elasticsearch.client.asCurrentUser.updateByQuery.mockResponse( - getSuccessfulSignalUpdateResponse() - ); - - const response = await server.inject(request, requestContextMock.convertContext(context)); - - context.core.elasticsearch.client.asCurrentUser.updateByQuery.mockRejectedValue( - new Error('Test error') - ); + const result = server.validate(request); - expect(response.body).toEqual({ - message: [`No alert ids were provided`], - status_code: 400, - }); + expect(result.badRequest).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts index 8b7e81f9bf8125..95d722ac0a3811 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts @@ -7,15 +7,14 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { uniq } from 'lodash/fp'; -import type { SetAlertTagsRequestBodyDecoded } from '../../../../../common/api/detection_engine/alert_tags'; -import { setAlertTagsRequestBody } from '../../../../../common/api/detection_engine/alert_tags'; +import { ManageAlertTagsRequestBody } from '../../../../../common/api/detection_engine/alert_tags'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DEFAULT_ALERTS_INDEX, DETECTION_ENGINE_ALERT_TAGS_URL, } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { validateAlertTagsArrays } from './helpers'; export const setAlertTagsRoute = (router: SecuritySolutionPluginRouter) => { @@ -32,10 +31,7 @@ export const setAlertTagsRoute = (router: SecuritySolutionPluginRouter) => { version: '2023-10-31', validate: { request: { - body: buildRouteValidation< - typeof setAlertTagsRequestBody, - SetAlertTagsRequestBodyDecoded - >(setAlertTagsRequestBody), + body: buildRouteValidationWithZod(ManageAlertTagsRequestBody), }, }, }, diff --git a/x-pack/test/api_integration/services/security_solution_api.gen.ts b/x-pack/test/api_integration/services/security_solution_api.gen.ts index 7650153c53ca30..4bc611e50bba2d 100644 --- a/x-pack/test/api_integration/services/security_solution_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_api.gen.ts @@ -19,18 +19,22 @@ import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST, } from '@kbn/core-http-common'; +import { AlertsMigrationCleanupRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.gen'; import { BulkCreateRulesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.gen'; import { BulkDeleteRulesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.gen'; import { BulkPatchRulesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.gen'; import { BulkUpdateRulesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.gen'; +import { CreateAlertsMigrationRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.gen'; import { CreateRuleRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.gen'; import { DeleteRuleRequestQueryInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.gen'; import { ExportRulesRequestQueryInput, ExportRulesRequestBodyInput, } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/export_rules/export_rules_route.gen'; +import { FinalizeAlertsMigrationRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.gen'; import { FindRulesRequestQueryInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/find_rules/find_rules_route.gen'; import { GetAgentPolicySummaryRequestQueryInput } from '@kbn/security-solution-plugin/common/api/endpoint/policy/policy.gen'; +import { GetAlertsMigrationStatusRequestQueryInput } from '@kbn/security-solution-plugin/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.gen'; import { GetEndpointSuggestionsRequestParamsInput, GetEndpointSuggestionsRequestBodyInput, @@ -45,13 +49,16 @@ import { GetRuleExecutionResultsRequestParamsInput, } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.gen'; import { ImportRulesRequestQueryInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/import_rules/import_rules_route.gen'; +import { ManageAlertTagsRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.gen'; import { PatchRuleRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.gen'; import { PerformBulkActionRequestQueryInput, PerformBulkActionRequestBodyInput, } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen'; import { ReadRuleRequestQueryInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.gen'; +import { SearchAlertsRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/signals/query_signals/query_signals_route.gen'; import { SetAlertAssigneesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/alert_assignees/set_alert_assignees_route.gen'; +import { SetAlertsStatusRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.gen'; import { SuggestUserProfilesRequestQueryInput } from '@kbn/security-solution-plugin/common/api/detection_engine/users/suggest_user_profiles_route.gen'; import { UpdateRuleRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.gen'; import { FtrProviderContext } from '../ftr_provider_context'; @@ -60,6 +67,22 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) const supertest = getService('supertest'); return { + /** + * Migrations favor data integrity over shard size. Consequently, unused or orphaned indices are artifacts of +the migration process. A successful migration will result in both the old and new indices being present. +As such, the old, orphaned index can (and likely should) be deleted. While you can delete these indices manually, +the endpoint accomplishes this task by applying a deletion policy to the relevant index, causing it to be deleted +after 30 days. It also deletes other artifacts specific to the migration implementation. + + */ + alertsMigrationCleanup(props: AlertsMigrationCleanupProps) { + return supertest + .delete('/api/detection_engine/signals/migration') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send(props.body as object); + }, /** * Creates new detection rules in bulk. */ @@ -104,6 +127,14 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(props.body as object); }, + createAlertsMigration(props: CreateAlertsMigrationProps) { + return supertest + .post('/api/detection_engine/signals/migration') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send(props.body as object); + }, /** * Create a single detection rule */ @@ -138,6 +169,20 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) .send(props.body as object) .query(props.query); }, + /** + * The finalization endpoint replaces the original index's alias with the successfully migrated index's alias. +The endpoint is idempotent; therefore, it can safely be used to poll a given migration and, upon completion, +finalize it. + + */ + finalizeAlertsMigration(props: FinalizeAlertsMigrationProps) { + return supertest + .post('/api/detection_engine/signals/finalize_migration') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send(props.body as object); + }, /** * Finds rules that match the given query. */ @@ -157,6 +202,14 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .query(props.query); }, + getAlertsMigrationStatus(props: GetAlertsMigrationStatusProps) { + return supertest + .post('/api/detection_engine/signals/migration_status') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .query(props.query); + }, getEndpointSuggestions(props: GetEndpointSuggestionsProps) { return supertest .post(replaceParams('/api/endpoint/suggestions/{suggestion_type}', props.params)) @@ -218,6 +271,14 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); }, + manageAlertTags(props: ManageAlertTagsProps) { + return supertest + .post('/api/detection_engine/signals/tags') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send(props.body as object); + }, /** * Patch a single rule */ @@ -259,6 +320,14 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); }, + searchAlerts(props: SearchAlertsProps) { + return supertest + .post('/api/detection_engine/signals/search') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send(props.body as object); + }, /** * Assigns users to alerts. */ @@ -270,6 +339,14 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(props.body as object); }, + setAlertsStatus(props: SetAlertsStatusProps) { + return supertest + .post('/api/detection_engine/signals/status') + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send(props.body as object); + }, /** * Suggests user profiles. */ @@ -295,6 +372,9 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) }; } +export interface AlertsMigrationCleanupProps { + body: AlertsMigrationCleanupRequestBodyInput; +} export interface BulkCreateRulesProps { body: BulkCreateRulesRequestBodyInput; } @@ -307,6 +387,9 @@ export interface BulkPatchRulesProps { export interface BulkUpdateRulesProps { body: BulkUpdateRulesRequestBodyInput; } +export interface CreateAlertsMigrationProps { + body: CreateAlertsMigrationRequestBodyInput; +} export interface CreateRuleProps { body: CreateRuleRequestBodyInput; } @@ -317,12 +400,18 @@ export interface ExportRulesProps { query: ExportRulesRequestQueryInput; body: ExportRulesRequestBodyInput; } +export interface FinalizeAlertsMigrationProps { + body: FinalizeAlertsMigrationRequestBodyInput; +} export interface FindRulesProps { query: FindRulesRequestQueryInput; } export interface GetAgentPolicySummaryProps { query: GetAgentPolicySummaryRequestQueryInput; } +export interface GetAlertsMigrationStatusProps { + query: GetAlertsMigrationStatusRequestQueryInput; +} export interface GetEndpointSuggestionsProps { params: GetEndpointSuggestionsRequestParamsInput; body: GetEndpointSuggestionsRequestBodyInput; @@ -341,6 +430,9 @@ export interface GetRuleExecutionResultsProps { export interface ImportRulesProps { query: ImportRulesRequestQueryInput; } +export interface ManageAlertTagsProps { + body: ManageAlertTagsRequestBodyInput; +} export interface PatchRuleProps { body: PatchRuleRequestBodyInput; } @@ -351,9 +443,15 @@ export interface PerformBulkActionProps { export interface ReadRuleProps { query: ReadRuleRequestQueryInput; } +export interface SearchAlertsProps { + body: SearchAlertsRequestBodyInput; +} export interface SetAlertAssigneesProps { body: SetAlertAssigneesRequestBodyInput; } +export interface SetAlertsStatusProps { + body: SetAlertsStatusRequestBodyInput; +} export interface SuggestUserProfilesProps { query: SuggestUserProfilesRequestQueryInput; } diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/ess_specific_index_logic/migrations/create_alerts_migrations.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/ess_specific_index_logic/migrations/create_alerts_migrations.ts index 389527a532b400..12058ababe0dc6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/ess_specific_index_logic/migrations/create_alerts_migrations.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/ess_specific_index_logic/migrations/create_alerts_migrations.ts @@ -70,11 +70,14 @@ export default ({ getService }: FtrProviderContext): void => { // Finalize the migration after each test so that the .siem-signals alias gets added to the migrated index - // this allows deleteSignalsIndex to find and delete the migrated index await sleep(5000); // Allow the migration to complete - await supertest - .post(DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL) - .set('kbn-xsrf', 'true') - .send({ migration_ids: createdMigrations.map((m) => m.migration_id) }) - .expect(200); + + if (createdMigrations.length > 0) { + await supertest + .post(DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL) + .set('kbn-xsrf', 'true') + .send({ migration_ids: createdMigrations.map((m) => m.migration_id) }) + .expect(200); + } await esArchiver.unload('x-pack/test/functional/es_archives/signals/outdated_signals_index'); await esArchiver.unload('x-pack/test/functional/es_archives/signals/legacy_signals_index'); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/field_aliases.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/field_aliases.ts index b6c6d265c14da1..732bb54385a8a9 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/field_aliases.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/field_aliases.ts @@ -39,12 +39,9 @@ export default ({ getService }: FtrProviderContext) => { }); beforeEach(async () => { - await createAlertsIndex(supertest, log); - }); - - afterEach(async () => { await deleteAllAlerts(supertest, log, es); await deleteAllRules(supertest, log); + await createAlertsIndex(supertest, log); }); it('should keep the original alias value such as "host_alias" from a source index when the value is indexed', async () => { diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/query_alerts.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/query_alerts.ts index 95764a6894fd44..63875d58f5d902 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/query_alerts.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/query_alerts.ts @@ -35,6 +35,10 @@ export default ({ getService }: FtrProviderContext) => { const es = getService('es'); describe('@ess @serverless @serverlessQA query_signals_route and find_alerts_route', () => { + beforeEach(async () => { + await deleteAllAlerts(supertest, log, es); + }); + describe('validation checks', () => { it('should not give errors when querying and the alerts index does exist and is empty', async () => { await createAlertsIndex(supertest, log); @@ -61,7 +65,7 @@ export default ({ getService }: FtrProviderContext) => { }); describe('runtime fields', () => { - before(async () => { + beforeEach(async () => { await esArchiver.load( 'x-pack/test/functional/es_archives/security_solution/alerts/8.8.0_multiple_docs', { @@ -71,7 +75,7 @@ export default ({ getService }: FtrProviderContext) => { ); await createAlertsIndex(supertest, log); }); - after(async () => { + afterEach(async () => { await deleteAllAlerts(supertest, log, es); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/set_alert_tags.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/set_alert_tags.ts index e0b09a111ae0ce..961150d0908c20 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/set_alert_tags.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/set_alert_tags.ts @@ -5,7 +5,7 @@ * 2.0. */ -import expect from '@kbn/expect'; +import expect from 'expect'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { @@ -49,9 +49,10 @@ export default ({ getService }: FtrProviderContext) => { .send(setAlertTags({ tagsToAdd: [], tagsToRemove: [], ids: [] })) .expect(400); - expect(body).to.eql({ - message: ['No alert ids were provided'], - status_code: 400, + expect(body).toEqual({ + error: 'Bad Request', + message: '[request body]: ids: Array must contain at least 1 element(s)', + statusCode: 400, }); }); @@ -62,7 +63,7 @@ export default ({ getService }: FtrProviderContext) => { .send(setAlertTags({ tagsToAdd: ['test-1'], tagsToRemove: ['test-1'], ids: ['123'] })) .expect(400); - expect(body).to.eql({ + expect(body).toEqual({ message: [ 'Duplicate tags ["test-1"] were found in the tags_to_add and tags_to_remove parameters.', ], @@ -119,7 +120,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); body.hits.hits.map((alert) => { - expect(alert._source?.['kibana.alert.workflow_tags']).to.eql(['tag-1']); + expect(alert._source?.['kibana.alert.workflow_tags']).toEqual(['tag-1']); }); }); @@ -165,7 +166,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); body.hits.hits.map((alert) => { - expect(alert._source?.['kibana.alert.workflow_tags']).to.eql(['tag-1']); + expect(alert._source?.['kibana.alert.workflow_tags']).toEqual(['tag-1']); }); }); @@ -211,7 +212,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); body.hits.hits.map((alert) => { - expect(alert._source?.['kibana.alert.workflow_tags']).to.eql(['tag-1']); + expect(alert._source?.['kibana.alert.workflow_tags']).toEqual(['tag-1']); }); }); @@ -245,7 +246,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); body.hits.hits.map((alert) => { - expect(alert._source?.['kibana.alert.workflow_tags']).to.eql([]); + expect(alert._source?.['kibana.alert.workflow_tags']).toEqual([]); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/set_alert_tags.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/set_alert_tags.ts index b3ae1d4de0b5c8..f8266297411799 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/set_alert_tags.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/alerts/set_alert_tags.ts @@ -6,7 +6,7 @@ */ import { AlertTagIds } from '@kbn/security-solution-plugin/common/api/detection_engine'; -import { SetAlertTagsRequestBody } from '@kbn/security-solution-plugin/common/api/detection_engine'; +import { ManageAlertTagsRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine'; export const setAlertTags = ({ tagsToAdd, @@ -16,7 +16,7 @@ export const setAlertTags = ({ tagsToAdd: string[]; tagsToRemove: string[]; ids: AlertTagIds; -}): SetAlertTagsRequestBody => ({ +}): ManageAlertTagsRequestBodyInput => ({ tags: { tags_to_add: tagsToAdd, tags_to_remove: tagsToRemove, From cc7dee61d2f8927f0c6c24d5754cf8c639b4c86d Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 18 Jun 2024 11:55:00 -0400 Subject: [PATCH 040/123] [Synthetics] Fix TLS cert view for > 3 monitors per cert (#186204) ## Summary Resolves #183985. This patch makes it so we can see more than three monitors per cert in the TLS page of Synthetics. I've set the default limit to the round number of 100. Realistically, users could have more than 100 monitors for the same cert, but also realistically, this page would need a layout overhaul to display that many monitors in a single row as well. ### Before image ### After image ## Testing this PR Follow the simple repro instructions in the linked issue. On `main`, you should only see 3 or less monitors. On this branch, you should see all monitors. --- .../synthetics/common/requests/get_certs_request_body.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/observability_solution/synthetics/common/requests/get_certs_request_body.ts b/x-pack/plugins/observability_solution/synthetics/common/requests/get_certs_request_body.ts index f4535f2f85b729..fa1bd9eafad327 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/requests/get_certs_request_body.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/requests/get_certs_request_body.ts @@ -151,6 +151,7 @@ export const getCertsRequestBody = ({ collapse: { field: 'tls.server.hash.sha256', inner_hits: { + size: 100, _source: { includes: ['monitor.id', 'monitor.name', 'url.full', 'config_id'], }, From 946a255bc5450c577546237bf450a99637632427 Mon Sep 17 00:00:00 2001 From: Tomasz Kajtoch Date: Tue, 18 Jun 2024 17:55:26 +0200 Subject: [PATCH 041/123] Upgrade EUI to v95.0.0 (#185943) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `v94.6.0` ⏩ `v95.0.0-backport.0` _[Questions? Please see our Kibana upgrade FAQ.](https://github.com/elastic/eui/blob/main/wiki/eui-team-processes/upgrading-kibana.md#faq-for-kibana-teams)_ --- ## [`v95.0.0-backport.0`](https://github.com/elastic/eui/releases/v95.0.0-backport.0) **This is a backport release only intended for use by Kibana.** - Updated `EuiSteps` to support a new `titleSize="xxs"` style, which outputs the same title font size but smaller unnumbered step indicators ([#7813](https://github.com/elastic/eui/pull/7813)) - Updated `EuiStepsHorizontal` to support a new `size="xs"` style, which outputs smaller unnumbered step indicators ([#7813](https://github.com/elastic/eui/pull/7813)) - Updated `EuiStepNumber` to support new `titleSize="none"` which omits rendering step numbers, and will only render icons ([#7813](https://github.com/elastic/eui/pull/7813)) ## [`v95.0.0`](https://github.com/elastic/eui/releases/v95.0.0) - Added `move` glyph to `EuiIcon` ([#7789](https://github.com/elastic/eui/pull/7789)) - Updated `EuiBasicTable` and `EuiInMemoryTable`s with `selection` - the header row checkbox will now render an indeterminate state if some (but not all) rows are selected ([#7817](https://github.com/elastic/eui/pull/7817)) **Bug fixes** - Fixed an `EuiDataGrid` visual bug when using `lineCount` row heights where the clamped text was still visible for some font sizes ([#7793](https://github.com/elastic/eui/pull/7793)) - Fixed `EuiSearchBar`'s filter configs to always respect `autoClose: false` ([#7806](https://github.com/elastic/eui/pull/7806)) **Breaking changes** - Removed deprecated `EUI_CHARTS_THEME_DARK`, `EUI_CHARTS_THEME_LIGHT` and `EUI_SPARKLINE_THEME_PARTIAL` exports ([#7682](https://github.com/elastic/eui/pull/7682)) - Removed deprecated `euiPalettePositive` and `euiPaletteNegative`. Use `euiPaletteGreen` and `euiPaletteRed` instead ([#7808](https://github.com/elastic/eui/pull/7808)) - Removed `type="inList"` from `EuiCheckbox`. Simply omit passing a `label` prop to render this style of checkbox ([#7814](https://github.com/elastic/eui/pull/7814)) - Removed the unused `compressed` prop from `EuiCheckbox` and `EuiRadio`. This prop was not doing anything on individual components. ([#7818](https://github.com/elastic/eui/pull/7818)) **CSS-in-JS conversions** - Converted `EuiCheckboxGroup` to Emotion ([#7818](https://github.com/elastic/eui/pull/7818)) - Converted `EuiRadioGroup` to Emotion ([#7818](https://github.com/elastic/eui/pull/7818)) --------- Co-authored-by: Cee Chen Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Cee Chen <549407+cee-chen@users.noreply.github.com> --- .../app/pages/page_reducer_stream/index.tsx | 3 --- .../app/pages/page_redux_stream/index.tsx | 3 --- .../pages/page_simple_string_stream/index.tsx | 1 - package.json | 2 +- .../__snapshots__/i18n_service.test.tsx.snap | 1 + .../src/i18n_eui_mapping.tsx | 3 +++ .../kbn-ui-shared-deps-npm/webpack.config.js | 1 - .../kbn-ui-shared-deps-src/src/definitions.js | 1 - packages/kbn-ui-shared-deps-src/src/entry.js | 1 - src/dev/license_checker/config.ts | 2 +- .../component/control_group_component.tsx | 1 - .../system_prompt_settings.tsx | 1 - .../views/multi_checkbox_facets_view.tsx | 1 - .../cypress/e2e/fleet_settings_outputs.cy.ts | 20 ++++++++++--------- .../fleet/cypress/screens/fleet_outputs.ts | 8 ++++---- .../output_form_kafka_partitioning.tsx | 2 +- .../screens/detail/settings/update_button.tsx | 1 - .../actions_section.test.js.snap | 18 ----------------- .../rule_editor_flyout.test.js.snap | 6 ------ .../scope_expression.test.js.snap | 12 ----------- .../__snapshots__/scope_section.test.js.snap | 15 -------------- .../imported_events.test.js.snap | 3 --- .../waterfall/waterfall_filter.tsx | 1 - .../kibana/feature_table/sub_feature_form.tsx | 1 - .../expression/es_query_expression.tsx | 4 +++- .../functional/tests/feature_control.ts | 3 +-- yarn.lock | 8 ++++---- 27 files changed, 30 insertions(+), 93 deletions(-) diff --git a/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx b/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx index a471d6f5890347..4bded9ac1e27f4 100644 --- a/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx +++ b/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx @@ -132,21 +132,18 @@ export const PageReducerStream: FC = () => { label="Simulate errors (gets applied to new streams only, not currently running ones)." checked={simulateErrors} onChange={(e) => setSimulateErrors(!simulateErrors)} - compressed /> setCompressResponse(!compressResponse)} - compressed /> setFlushFix(!flushFix)} - compressed /> diff --git a/examples/response_stream/public/containers/app/pages/page_redux_stream/index.tsx b/examples/response_stream/public/containers/app/pages/page_redux_stream/index.tsx index aaf0a7b5dbbb7a..15512ac92d12d8 100644 --- a/examples/response_stream/public/containers/app/pages/page_redux_stream/index.tsx +++ b/examples/response_stream/public/containers/app/pages/page_redux_stream/index.tsx @@ -136,21 +136,18 @@ export const PageReduxStream: FC = () => { label="Simulate errors (gets applied to new streams only, not currently running ones)." checked={simulateErrors} onChange={(e) => dispatch(setSimulateErrors(!simulateErrors))} - compressed /> dispatch(setCompressResponse(!compressResponse))} - compressed /> dispatch(setFlushFix(!flushFix))} - compressed /> diff --git a/examples/response_stream/public/containers/app/pages/page_simple_string_stream/index.tsx b/examples/response_stream/public/containers/app/pages/page_simple_string_stream/index.tsx index 3e33ade3814891..981329dfcec3a9 100644 --- a/examples/response_stream/public/containers/app/pages/page_simple_string_stream/index.tsx +++ b/examples/response_stream/public/containers/app/pages/page_simple_string_stream/index.tsx @@ -83,7 +83,6 @@ export const PageSimpleStringStream: FC = () => { label="Toggle compression setting for response stream." checked={compressResponse} onChange={(e) => setCompressResponse(!compressResponse)} - compressed /> diff --git a/package.json b/package.json index d8934593517833..0c50f51a82f2e5 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "@elastic/ecs": "^8.11.1", "@elastic/elasticsearch": "^8.13.1", "@elastic/ems-client": "8.5.1", - "@elastic/eui": "94.6.0", + "@elastic/eui": "95.0.0-backport.0", "@elastic/filesaver": "1.1.2", "@elastic/node-crypto": "1.2.1", "@elastic/numeral": "^2.5.1", diff --git a/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap b/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap index fd8ba14e035cfc..67fe5f2a462215 100644 --- a/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap +++ b/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap @@ -12,6 +12,7 @@ exports[`#start() returns \`Context\` component 1`] = ` "euiAutoRefresh.autoRefreshLabel": "Auto refresh", "euiAutoRefresh.buttonLabelOff": "Auto refresh is off", "euiAutoRefresh.buttonLabelOn": [Function], + "euiBasicTable.deselectRows": "Deselect rows", "euiBasicTable.noItemsMessage": "No items found", "euiBasicTable.selectAllRows": "Select all rows", "euiBasicTable.selectThisRow": [Function], diff --git a/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx index 4d6fcf64ab0819..151a94bd3ce228 100644 --- a/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx +++ b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx @@ -85,6 +85,9 @@ export const getEuiContextMapping = (): EuiTokensObject => { 'euiBasicTable.noItemsMessage': i18n.translate('core.euiBasicTable.noItemsMessage', { defaultMessage: 'No items found', }), + 'euiBasicTable.deselectRows': i18n.translate('core.euiBasicTable.deselectRows', { + defaultMessage: 'Deselect rows', + }), 'euiBottomBar.customScreenReaderAnnouncement': ({ landmarkHeading }: EuiValues) => i18n.translate('core.euiBottomBar.customScreenReaderAnnouncement', { defaultMessage: diff --git a/packages/kbn-ui-shared-deps-npm/webpack.config.js b/packages/kbn-ui-shared-deps-npm/webpack.config.js index 79502207aea00c..24085109d0d564 100644 --- a/packages/kbn-ui-shared-deps-npm/webpack.config.js +++ b/packages/kbn-ui-shared-deps-npm/webpack.config.js @@ -63,7 +63,6 @@ module.exports = (_, argv) => { '@elastic/eui/optimize/es/components/provider/nested', '@elastic/eui/optimize/es/services', '@elastic/eui/optimize/es/services/format', - '@elastic/eui/dist/eui_charts_theme', '@elastic/eui/dist/eui_theme_light.json', '@elastic/eui/dist/eui_theme_dark.json', '@elastic/numeral', diff --git a/packages/kbn-ui-shared-deps-src/src/definitions.js b/packages/kbn-ui-shared-deps-src/src/definitions.js index 78ee1229da4e97..b2b38e131fb804 100644 --- a/packages/kbn-ui-shared-deps-src/src/definitions.js +++ b/packages/kbn-ui-shared-deps-src/src/definitions.js @@ -75,7 +75,6 @@ const externals = { '__kbnSharedDeps__.ElasticEuiLibComponentsUseIsNestedEuiProvider', '@elastic/eui/lib/services': '__kbnSharedDeps__.ElasticEuiLibServices', '@elastic/eui/lib/services/format': '__kbnSharedDeps__.ElasticEuiLibServicesFormat', - '@elastic/eui/dist/eui_charts_theme': '__kbnSharedDeps__.ElasticEuiChartsTheme', // transient dep of eui '@hello-pangea/dnd': '__kbnSharedDeps__.HelloPangeaDnd', diff --git a/packages/kbn-ui-shared-deps-src/src/entry.js b/packages/kbn-ui-shared-deps-src/src/entry.js index b012cb56601138..1d0e88ef0efd83 100644 --- a/packages/kbn-ui-shared-deps-src/src/entry.js +++ b/packages/kbn-ui-shared-deps-src/src/entry.js @@ -42,7 +42,6 @@ export const ElasticEui = require('@elastic/eui'); export const ElasticEuiLibComponentsUseIsNestedEuiProvider = require('@elastic/eui/optimize/es/components/provider/nested'); export const ElasticEuiLibServices = require('@elastic/eui/optimize/es/services'); export const ElasticEuiLibServicesFormat = require('@elastic/eui/optimize/es/services/format'); -export const ElasticEuiChartsTheme = require('@elastic/eui/dist/eui_charts_theme'); export const KbnDatemath = require('@kbn/datemath'); export const HelloPangeaDnd = require('@hello-pangea/dnd/dist/dnd'); export const ReduxjsToolkit = require('@reduxjs/toolkit'); diff --git a/src/dev/license_checker/config.ts b/src/dev/license_checker/config.ts index b7642cf7e9af7b..45262fd3a57cc4 100644 --- a/src/dev/license_checker/config.ts +++ b/src/dev/license_checker/config.ts @@ -86,7 +86,7 @@ export const LICENSE_OVERRIDES = { 'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts '@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint '@elastic/ems-client@8.5.1': ['Elastic License 2.0'], - '@elastic/eui@94.6.0': ['SSPL-1.0 OR Elastic License 2.0'], + '@elastic/eui@95.0.0-backport.0': ['SSPL-1.0 OR Elastic License 2.0'], 'language-subtag-registry@0.3.21': ['CC-BY-4.0'], // retired ODC‑By license https://github.com/mattcg/language-subtag-registry 'buffers@0.1.1': ['MIT'], // license in importing module https://www.npmjs.com/package/binary '@bufbuild/protobuf@1.2.1': ['Apache-2.0'], // license (Apache-2.0 AND BSD-3-Clause) diff --git a/src/plugins/controls/public/control_group/component/control_group_component.tsx b/src/plugins/controls/public/control_group/component/control_group_component.tsx index 56a50e596870cb..019ef9256e91b5 100644 --- a/src/plugins/controls/public/control_group/component/control_group_component.tsx +++ b/src/plugins/controls/public/control_group/component/control_group_component.tsx @@ -168,7 +168,6 @@ export const ControlGroup = () => { content={ControlGroupStrings.invalidControlWarning.getTourContent(invalidControlType)} footerAction={[ = React.memo( } checked={isNewConversationDefault} onChange={handleNewConversationDefaultChange} - compressed /> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/multi_checkbox_facets_view.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/multi_checkbox_facets_view.tsx index 4ddd0920038e1b..19727db552acf1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/multi_checkbox_facets_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/multi_checkbox_facets_view.tsx @@ -84,7 +84,6 @@ export const MultiCheckboxFacetsView: React.FC = ({ options={checkboxGroupOptions} idToSelectedMap={idToSelectedMap} onChange={onChange} - compressed /> {showMore && ( <> diff --git a/x-pack/plugins/fleet/cypress/e2e/fleet_settings_outputs.cy.ts b/x-pack/plugins/fleet/cypress/e2e/fleet_settings_outputs.cy.ts index 965dcf48eed6e8..4fc4fa33ea5b05 100644 --- a/x-pack/plugins/fleet/cypress/e2e/fleet_settings_outputs.cy.ts +++ b/x-pack/plugins/fleet/cypress/e2e/fleet_settings_outputs.cy.ts @@ -281,7 +281,7 @@ queue: }); // Verify SSL fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SSL_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SSL_OPTION).find('label').click(); cy.get('[placeholder="Specify certificate authority"]'); cy.get('[placeholder="Specify ssl certificate"]'); cy.get('[placeholder="Specify certificate key"]'); @@ -292,7 +292,7 @@ queue: // Verify None fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_NONE_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_NONE_OPTION).find('label').click(); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SELECT).should('not.exist'); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_INPUT).should('not.exist'); @@ -308,14 +308,16 @@ queue: cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_PLAIN_OPTION); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_ENCRYPTION_OPTION); - cy.getBySel( - SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_ENCRYPTION_OPTION - ).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_CONNECTION_TYPE_ENCRYPTION_OPTION) + .find('label') + .click(); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_VERIFICATION_MODE_INPUT); cy.get('[placeholder="Specify certificate authority"]'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION) + .find('label') + .click(); // Verify Partitioning fields cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_PANEL).within(() => { @@ -327,13 +329,13 @@ queue: }); // Verify Round Robin fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION).find('label').click(); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_EVENTS_INPUT); // Verify Hash fields - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_OPTION).find('label').click(); cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_INPUT); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_RANDOM_OPTION).find('label').click(); // Topics cy.getBySel(SETTINGS_OUTPUTS_KAFKA.TOPICS_PANEL).within(() => { diff --git a/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts b/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts index eb4d3310e113d7..763e6fae1b1efb 100644 --- a/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts +++ b/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts @@ -31,7 +31,7 @@ export const selectKafkaOutput = () => { visit('/app/fleet/settings'); cy.getBySel(SETTINGS_OUTPUTS.ADD_BTN).click(); cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).select('kafka'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION).find('label').click(); }; export const shouldDisplayError = (handler: string) => { @@ -190,8 +190,8 @@ export const fillInKafkaOutputForm = (create?: boolean) => { ); cy.get('[placeholder="Specify certificate authority"]').clear().type('testCA'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SCRAM_256_OPTION).click(); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_SASL_SCRAM_256_OPTION).find('label').click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.PARTITIONING_HASH_OPTION).find('label').click(); cy.getBySel(kafkaOutputFormValues.hash.selector).type(kafkaOutputFormValues.hash.value); cy.getBySel(kafkaOutputFormValues.defaultTopic.selector).type( @@ -265,7 +265,7 @@ export const validateOutputTypeChangeToKafka = (outputId: string) => { visit(`/app/fleet/settings/outputs/${outputId}`); cy.getBySel(kafkaOutputFormValues.name.selector).clear(); cy.getBySel(SETTINGS_OUTPUTS.TYPE_INPUT).select('kafka'); - cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION).click(); + cy.getBySel(SETTINGS_OUTPUTS_KAFKA.AUTHENTICATION_USERNAME_PASSWORD_OPTION).find('label').click(); fillInKafkaOutputForm(true); cy.intercept('PUT', '**/api/fleet/outputs/**').as('saveOutput'); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_partitioning.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_partitioning.tsx index 6acb44fe33af5c..d5f7de712cd869 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_partitioning.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_partitioning.tsx @@ -140,7 +140,7 @@ export const OutputFormKafkaPartitioning: React.FunctionComponent<{ } > = ({ {packagePolicyCount > 0 && ( @@ -393,10 +391,8 @@ exports[`RuleEditorFlyout renders the flyout after setting the rule to edit 1`] @@ -629,10 +625,8 @@ exports[`RuleEditorFlyout renders the flyout for creating a rule with conditions diff --git a/x-pack/plugins/ml/public/application/components/rule_editor/__snapshots__/scope_expression.test.js.snap b/x-pack/plugins/ml/public/application/components/rule_editor/__snapshots__/scope_expression.test.js.snap index 4347958d240c0a..f5b266b67062cf 100644 --- a/x-pack/plugins/ml/public/application/components/rule_editor/__snapshots__/scope_expression.test.js.snap +++ b/x-pack/plugins/ml/public/application/components/rule_editor/__snapshots__/scope_expression.test.js.snap @@ -10,10 +10,7 @@ exports[`ScopeExpression renders when empty list of filter IDs is supplied 1`] = > @@ -46,10 +43,7 @@ exports[`ScopeExpression renders when enabled set to false 1`] = ` > @@ -190,10 +184,7 @@ exports[`ScopeExpression renders when filter ID and type supplied 1`] = ` > @@ -334,10 +325,7 @@ exports[`ScopeExpression renders when no filter ID or type supplied 1`] = ` > diff --git a/x-pack/plugins/ml/public/application/components/rule_editor/__snapshots__/scope_section.test.js.snap b/x-pack/plugins/ml/public/application/components/rule_editor/__snapshots__/scope_section.test.js.snap index c61f9a3d30d7d0..110530cd03e970 100644 --- a/x-pack/plugins/ml/public/application/components/rule_editor/__snapshots__/scope_section.test.js.snap +++ b/x-pack/plugins/ml/public/application/components/rule_editor/__snapshots__/scope_section.test.js.snap @@ -17,10 +17,7 @@ exports[`ScopeSection false canGetFilters privilege show NoPermissionCallOut whe /> 0)} id="onlyHighlighted" label={FILTER_COLLAPSE_REQUESTS_LABEL} diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx index 03ed9597fcb2db..4f3c1eb103a751 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx @@ -130,7 +130,6 @@ export const SubFeatureForm = (props: Props) => { }} checked={isGranted} disabled={props.disabled} - compressed={true} /> ); })} diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx index 0c749b175b2e60..fd68e61ecb9873 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/es_query_expression.tsx @@ -345,7 +345,9 @@ export const EsQueryExpression: React.FC< errors={errors} hasValidationErrors={hasExpressionValidationErrors(currentRuleParams, isServerless)} onTestFetch={onTestQuery} - excludeHitsFromPreviousRun={excludeHitsFromPreviousRun} + excludeHitsFromPreviousRun={ + excludeHitsFromPreviousRun ?? DEFAULT_VALUES.EXCLUDE_PREVIOUS_HITS + } onChangeExcludeHitsFromPreviousRun={useCallback( (exclude) => setParam('excludeHitsFromPreviousRun', exclude), [setParam] diff --git a/x-pack/test/saved_object_tagging/functional/tests/feature_control.ts b/x-pack/test/saved_object_tagging/functional/tests/feature_control.ts index f2264231004511..463c2f5be82f42 100644 --- a/x-pack/test/saved_object_tagging/functional/tests/feature_control.ts +++ b/x-pack/test/saved_object_tagging/functional/tests/feature_control.ts @@ -45,8 +45,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const unselectTags = async () => { if (await tagManagementPage.isSelectionColumnDisplayed()) { - await tagManagementPage.selectAllTagRows(); - await tagManagementPage.selectAllTagRows(); + await tagManagementPage.clickOnBulkAction('clear_selection'); } }; diff --git a/yarn.lock b/yarn.lock index 834ac4b0583564..07416bc65a2e43 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1720,10 +1720,10 @@ resolved "https://registry.yarnpkg.com/@elastic/eslint-plugin-eui/-/eslint-plugin-eui-0.0.2.tgz#56b9ef03984a05cc213772ae3713ea8ef47b0314" integrity sha512-IoxURM5zraoQ7C8f+mJb9HYSENiZGgRVcG4tLQxE61yHNNRDXtGDWTZh8N1KIHcsqN1CEPETjuzBXkJYF/fDiQ== -"@elastic/eui@94.6.0": - version "94.6.0" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-94.6.0.tgz#fd56be1dbdcdea259cdb3504085c8479fa35bcef" - integrity sha512-lYXVcylXn4Iz2WumBuOEkc1PRFoUby7CTnNhTS/gVrbTP7Mn0ombcoPFUSiZcA7VuN2mHfPmTUdBQptC/apTzA== +"@elastic/eui@95.0.0-backport.0": + version "95.0.0-backport.0" + resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-95.0.0-backport.0.tgz#6fdfbc813259cf82896f24641bb6e8a03587f3e8" + integrity sha512-aaCQYLdJ4/1uQUb8xsToa94HwUDN2HSjtZzrgh3iT3El7tieNk6TNzX9QtNePw9M57snpdt41wyg6QFM7Jhltg== dependencies: "@hello-pangea/dnd" "^16.6.0" "@types/lodash" "^4.14.202" From 641a71bb68259d2650e5071c6f333f661c3b8e2e Mon Sep 17 00:00:00 2001 From: "Eyo O. Eyo" <7893459+eokoneyo@users.noreply.github.com> Date: Tue, 18 Jun 2024 18:30:40 +0200 Subject: [PATCH 042/123] Improve logic for dashboard duplication title computation (#185056) ## Summary follow up to https://github.com/elastic/kibana/pull/184777#discussion_r1631353032 Previously, if a user has cloned a dashboard N times, in the worst case that the next duplication attempt is initiated from the initial dashboard N network calls would be required to find a unique title for the next uniquely titled clone. This update short circuits that process by querying for the last created dashboard, getting it's duplicationId, increment it and proposing it as the next dashboard duplicate title, with this approach there's still a chance we might suggest a dashboard title that's been claimed if the user modifies the dashboard title to a higher duplication Id after creation, especially that we are querying for the last created and this is situation we can't correct for, the resolution for the appropriate title in that case would be on the user. ## How to test - Create couple of duplicated dashboards, the titles should follow the normal increment progression ie. n+1 - Create some that skip the expected pattern by any increment of choice, on attempting to duplicate this dashboard the suggested title should be previous + 1 - Choose to duplicate any previously created dashboard the suggested title should be the increment of the last duplicated dashboard ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Catherine Liu --- .../embeddable/api/run_save_functions.tsx | 27 ++-- ...heck_for_duplicate_dashboard_title.test.ts | 120 ++++++++++++++++++ .../check_for_duplicate_dashboard_title.ts | 37 +++++- .../apps/dashboard/group4/dashboard_clone.ts | 15 +++ 4 files changed, 178 insertions(+), 21 deletions(-) create mode 100644 src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.test.ts diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx index 049bfaf00e5dde..67cad4bd7bf83d 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx @@ -275,21 +275,18 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo if (lastSavedId) { const [baseTitle, baseCount] = extractTitleAndCount(newTitle); - let copyCount = baseCount + 1; - newTitle = `${baseTitle} (${copyCount})`; - - // increment count until we find a unique title - while ( - !(await checkForDuplicateDashboardTitle({ - title: newTitle, - lastSavedTitle: currentState.title, - copyOnSave: true, - isTitleDuplicateConfirmed: false, - })) - ) { - copyCount++; - newTitle = `${baseTitle} (${copyCount})`; - } + + newTitle = `${baseTitle} (${baseCount + 1})`; + + await checkForDuplicateDashboardTitle({ + title: newTitle, + lastSavedTitle: currentState.title, + copyOnSave: true, + isTitleDuplicateConfirmed: false, + onTitleDuplicate(speculativeSuggestion) { + newTitle = speculativeSuggestion; + }, + }); switch (interactionMode) { case ViewMode.EDIT: { diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.test.ts b/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.test.ts new file mode 100644 index 00000000000000..edaae6a8b0d925 --- /dev/null +++ b/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.test.ts @@ -0,0 +1,120 @@ +/* + * 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 { ContentClient } from '@kbn/content-management-plugin/public'; +import { checkForDuplicateDashboardTitle } from './check_for_duplicate_dashboard_title'; +import { extractTitleAndCount } from '../../../dashboard_container/embeddable/api/lib/extract_title_and_count'; + +type ContentManagementStart = Parameters[1]; + +describe('checkForDuplicateDashboardTitle', () => { + const mockedContentManagementClient = { + search: jest.fn(), + } as unknown as ContentClient; + + const newTitle = 'Shiny dashboard (1)'; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('will only search using the dashboard basename', async () => { + const [baseDashboardName] = extractTitleAndCount(newTitle); + + const pageResults = [ + { + attributes: { + title: baseDashboardName, + }, + }, + ]; + + ( + mockedContentManagementClient.search as jest.MockedFunction + ).mockImplementationOnce(() => + Promise.resolve({ + hits: pageResults, + pagination: { + total: pageResults.length, + }, + }) + ); + + await checkForDuplicateDashboardTitle( + { + title: newTitle, + lastSavedTitle: baseDashboardName, + copyOnSave: true, + isTitleDuplicateConfirmed: false, + }, + { client: mockedContentManagementClient } as ContentManagementStart + ); + + expect(mockedContentManagementClient.search).toHaveBeenCalledWith( + expect.objectContaining({ + query: expect.objectContaining({ + text: `${baseDashboardName}*`, + }), + }) + ); + }); + + it('invokes onTitleDuplicate with a speculative collision free value when the new title provided is a duplicate match', async () => { + const [baseDashboardName] = extractTitleAndCount(newTitle); + + const userTitleInput = `${baseDashboardName} (10)`; + + const pageResults = [ + { + attributes: { + title: baseDashboardName, + }, + }, + ].concat( + Array.from(new Array(5)).map((_, idx) => ({ + attributes: { + title: `${baseDashboardName} (${10 + idx})`, + }, + })) + ); + + const onTitleDuplicate = jest.fn(); + + ( + mockedContentManagementClient.search as jest.MockedFunction + ).mockImplementationOnce(() => + Promise.resolve({ + hits: pageResults, + pagination: { + total: pageResults.length, + }, + }) + ); + + await checkForDuplicateDashboardTitle( + { + title: userTitleInput, + lastSavedTitle: baseDashboardName, + copyOnSave: true, + isTitleDuplicateConfirmed: false, + onTitleDuplicate, + }, + { client: mockedContentManagementClient } as ContentManagementStart + ); + + expect(mockedContentManagementClient.search).toHaveBeenCalledWith( + expect.objectContaining({ + query: expect.objectContaining({ + text: 'Shiny dashboard*', + }), + }) + ); + + expect(onTitleDuplicate).toHaveBeenCalledWith(`${baseDashboardName} (15)`); + }); +}); diff --git a/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.ts b/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.ts index 0ffcf8c9788e96..a4bd93191a4878 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management/lib/check_for_duplicate_dashboard_title.ts @@ -9,12 +9,16 @@ import { DashboardStartDependencies } from '../../../plugin'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; import { DashboardCrudTypes } from '../../../../common/content_management'; +import { extractTitleAndCount } from '../../../dashboard_container/embeddable/api/lib/extract_title_and_count'; export interface DashboardDuplicateTitleCheckProps { title: string; copyOnSave: boolean; lastSavedTitle: string; - onTitleDuplicate?: () => void; + /** + * invokes the onTitleDuplicate function if provided with a speculative title that should be collision free + */ + onTitleDuplicate?: (speculativeSuggestion: string) => void; isTitleDuplicateConfirmed: boolean; } @@ -33,6 +37,11 @@ export async function checkForDuplicateDashboardTitle( }: DashboardDuplicateTitleCheckProps, contentManagement: DashboardStartDependencies['contentManagement'] ): Promise { + // Don't check if the title is an empty string + if (!title) { + return true; + } + // Don't check for duplicates if user has already confirmed save with duplicate title if (isTitleDuplicateConfirmed) { return true; @@ -44,21 +53,37 @@ export async function checkForDuplicateDashboardTitle( return true; } + const [baseDashboardName] = extractTitleAndCount(title); + const { hits } = await contentManagement.client.search< DashboardCrudTypes['SearchIn'], DashboardCrudTypes['SearchOut'] >({ contentTypeId: DASHBOARD_CONTENT_ID, query: { - text: title ? `${title}*` : undefined, - limit: 10, + text: `${baseDashboardName}*`, + limit: 20, + }, + options: { + onlyTitle: true, }, - options: { onlyTitle: true }, }); - const duplicate = hits.find((hit) => hit.attributes.title.toLowerCase() === title.toLowerCase()); + + const duplicate = Boolean( + hits.find((hit) => hit.attributes.title.toLowerCase() === title.toLowerCase()) + ); + if (!duplicate) { return true; } - onTitleDuplicate?.(); + + const [largestDuplicationId] = hits + .map((hit) => extractTitleAndCount(hit.attributes.title)[1]) + .sort((a, b) => b - a); + + const speculativeCollisionFreeTitle = `${baseDashboardName} (${largestDuplicationId + 1})`; + + onTitleDuplicate?.(speculativeCollisionFreeTitle); + return false; } diff --git a/test/functional/apps/dashboard/group4/dashboard_clone.ts b/test/functional/apps/dashboard/group4/dashboard_clone.ts index 1e15f4d44e7405..25ad42ac10fe71 100644 --- a/test/functional/apps/dashboard/group4/dashboard_clone.ts +++ b/test/functional/apps/dashboard/group4/dashboard_clone.ts @@ -49,5 +49,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.gotoDashboardLandingPage(); await listingTable.searchAndExpectItemsCount('dashboard', `${dashboardName} (2)`, 1); }); + + it('Clone should always increment from the last duplicated dashboard with a unique title', async function () { + await PageObjects.dashboard.loadSavedDashboard(clonedDashboardName); + // force dashboard duplicate id to increment out of logical progression bounds + await PageObjects.dashboard.duplicateDashboard(`${dashboardName} (20)`); + await PageObjects.dashboard.gotoDashboardLandingPage(); + await listingTable.searchAndExpectItemsCount('dashboard', `${dashboardName} (20)`, 1); + // load dashboard with duplication id 1 + await PageObjects.dashboard.loadSavedDashboard(clonedDashboardName); + // run normal clone + await PageObjects.dashboard.duplicateDashboard(); + await PageObjects.dashboard.gotoDashboardLandingPage(); + // clone gets duplication id, that picks off from last duplicated dashboard + await listingTable.searchAndExpectItemsCount('dashboard', `${dashboardName} (21)`, 1); + }); }); } From 10de8203b8168d89e4e4bbe7192e0b7f313b09cd Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Tue, 18 Jun 2024 17:47:52 +0100 Subject: [PATCH 043/123] [Security Solution][Detection Engine] fixes and unskips new terms FTR tests (#186283) ## Summary - addresses https://github.com/elastic/kibana/issues/180236 - replaces kibana expect with jest expect --- .../execution_logic/new_terms.ts | 168 +++++++++++------- 1 file changed, 104 insertions(+), 64 deletions(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/new_terms.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/new_terms.ts index d6f464b63d78df..9e2638981a9e8f 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/new_terms.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/new_terms.ts @@ -5,7 +5,7 @@ * 2.0. */ -import expect from '@kbn/expect'; +import expect from 'expect'; import { v4 as uuidv4 } from 'uuid'; import { NewTermsRuleCreateProps } from '@kbn/security-solution-plugin/common/api/detection_engine'; @@ -80,8 +80,7 @@ export default ({ getService }: FtrProviderContext) => { return testId; }; - // Failing: See https://github.com/elastic/kibana/issues/180236 - describe.skip('@ess @serverless @serverlessQA New terms type rules', () => { + describe('@ess @serverless @serverlessQA New terms type rules', () => { before(async () => { await esArchiver.load(path); await esArchiver.load('x-pack/test/functional/es_archives/security_solution/new_terms'); @@ -110,8 +109,8 @@ export default ({ getService }: FtrProviderContext) => { const createdRule = await createRule(supertest, log, rule); const alerts = await getAlerts(supertest, log, es, createdRule); - expect(alerts.hits.hits.length).eql(1); - expect(removeRandomValuedPropertiesFromAlert(alerts.hits.hits[0]._source)).eql({ + expect(alerts.hits.hits.length).toEqual(1); + expect(removeRandomValuedPropertiesFromAlert(alerts.hits.hits[0]._source)).toEqual({ 'kibana.alert.new_terms': ['zeek-newyork-sha-aa8df15'], 'kibana.alert.rule.category': 'New Terms Rule', 'kibana.alert.rule.consumer': 'siem', @@ -145,12 +144,17 @@ export default ({ getService }: FtrProviderContext) => { version: '18.10 (Cosmic Cuttlefish)', }, }, - message: - 'Login by user root (UID: 0) on pts/0 (PID: 20638) from 8.42.77.171 (IP: 8.42.77.171)', + message: expect.stringMatching( + /Login by user (root|bob) \(UID: (0|1)\) on pts\/0 \(PID: 20638\) from 8\.42\.77\.171 \(IP: 8\.42\.77\.171\)/ + ), process: { pid: 20638 }, service: { type: 'system' }, source: { ip: '8.42.77.171' }, - user: { id: 0, name: 'root', terminal: 'pts/0' }, + user: { + id: expect.any(Number), + name: expect.stringMatching(/(root|bob)/), + terminal: 'pts/0', + }, 'event.action': 'user_login', 'event.category': 'authentication', 'event.dataset': 'login', @@ -162,7 +166,7 @@ export default ({ getService }: FtrProviderContext) => { 'kibana.alert.original_time': '2019-02-19T20:42:08.230Z', 'kibana.alert.ancestors': [ { - id: 'x07wJ2oB9v5HJNSHhyxi', + id: expect.any(String), type: 'event', index: 'auditbeat-8.0.0-2019.02.19-000001', depth: 0, @@ -173,8 +177,9 @@ export default ({ getService }: FtrProviderContext) => { 'kibana.alert.workflow_tags': [], 'kibana.alert.workflow_assignee_ids': [], 'kibana.alert.depth': 1, - 'kibana.alert.reason': - 'authentication event with source 8.42.77.171 by root on zeek-newyork-sha-aa8df15 created high alert Query with a rule id.', + 'kibana.alert.reason': expect.stringMatching( + /authentication event with source 8\.42\.77\.171 by (root|bob) on zeek-newyork-sha-aa8df15 created high alert Query with a rule id\./ + ), 'kibana.alert.severity': 'high', 'kibana.alert.risk_score': 55, 'kibana.alert.rule.parameters': { @@ -203,6 +208,9 @@ export default ({ getService }: FtrProviderContext) => { history_window_start: '2019-01-19T20:42:00.000Z', index: ['auditbeat-*'], language: 'kuery', + rule_source: { + type: 'internal', + }, }, 'kibana.alert.rule.actions': [], 'kibana.alert.rule.author': [], @@ -249,7 +257,7 @@ export default ({ getService }: FtrProviderContext) => { }; const { logs } = await previewRule({ supertest, rule }); - expect(logs[0].warnings).contain(getMaxAlertsWarning()); + expect(logs[0].warnings).toContain(getMaxAlertsWarning()); }); it("doesn't generate max alerts warning when circuit breaker is met but not exceeded", async () => { @@ -262,7 +270,7 @@ export default ({ getService }: FtrProviderContext) => { }; const { logs } = await previewRule({ supertest, rule }); - expect(logs[0].warnings).not.contain(getMaxAlertsWarning()); + expect(logs[0].warnings).not.toContain(getMaxAlertsWarning()); }); it('should generate 3 alerts when 1 document has 3 new values', async () => { @@ -276,19 +284,19 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(3); + expect(previewAlerts.length).toEqual(3); const previewAlertsOrderedByHostIp = orderBy( previewAlerts, '_source.kibana.alert.new_terms', 'asc' ); - expect(previewAlertsOrderedByHostIp[0]._source?.['kibana.alert.new_terms']).eql([ + expect(previewAlertsOrderedByHostIp[0]._source?.['kibana.alert.new_terms']).toEqual([ '10.10.0.6', ]); - expect(previewAlertsOrderedByHostIp[1]._source?.['kibana.alert.new_terms']).eql([ + expect(previewAlertsOrderedByHostIp[1]._source?.['kibana.alert.new_terms']).toEqual([ '157.230.208.30', ]); - expect(previewAlertsOrderedByHostIp[2]._source?.['kibana.alert.new_terms']).eql([ + expect(previewAlertsOrderedByHostIp[2]._source?.['kibana.alert.new_terms']).toEqual([ 'fe80::24ce:f7ff:fede:a571', ]); }); @@ -304,14 +312,14 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(3); + expect(previewAlerts.length).toEqual(3); const newTerms = orderBy( previewAlerts.map((item) => item._source?.['kibana.alert.new_terms']), ['0', '1'] ); - expect(newTerms).eql([ + expect(newTerms).toEqual([ ['zeek-newyork-sha-aa8df15', '10.10.0.6'], ['zeek-newyork-sha-aa8df15', '157.230.208.30'], ['zeek-newyork-sha-aa8df15', 'fe80::24ce:f7ff:fede:a571'], @@ -359,7 +367,7 @@ export default ({ getService }: FtrProviderContext) => { es, previewId: hostIpPreview.previewId, }); - expect(hostIpPreviewAlerts.length).eql(0); + expect(hostIpPreviewAlerts.length).toEqual(0); // shouldn't be terms for 'host.name' const hostNamePreview = await previewRule({ @@ -370,14 +378,14 @@ export default ({ getService }: FtrProviderContext) => { es, previewId: hostNamePreview.previewId, }); - expect(hostNamePreviewAlerts.length).eql(0); + expect(hostNamePreviewAlerts.length).toEqual(0); const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(1); + expect(previewAlerts.length).toEqual(1); - expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['host-0', '127.0.0.2']); + expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).toEqual(['host-0', '127.0.0.2']); }); it('should generate 5 alerts, 1 for each new unique combination in 2 fields', async () => { @@ -416,14 +424,14 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(5); + expect(previewAlerts.length).toEqual(5); const newTerms = orderBy( previewAlerts.map((item) => item._source?.['kibana.alert.new_terms']), ['0', '1'] ); - expect(newTerms).eql([ + expect(newTerms).toEqual([ ['192.168.1.1', 'tag-new-1'], ['192.168.1.1', 'tag-new-3'], ['192.168.1.2', 'tag-2'], @@ -456,8 +464,8 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(1); - expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['user-0', '1']); + expect(previewAlerts.length).toEqual(1); + expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).toEqual(['user-0', 1]); }); it('should generate 1 alert for unique combination of terms, one of which is a boolean', async () => { @@ -472,8 +480,8 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(1); - expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['user-0', false]); + expect(previewAlerts.length).toEqual(1); + expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).toEqual(['user-0', false]); }); it('should generate alerts for every term when history window is small', async () => { @@ -488,15 +496,15 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(5); + expect(previewAlerts.length).toEqual(5); const hostNames = previewAlerts .map((signal) => signal._source?.['kibana.alert.new_terms']) .sort(); - expect(hostNames[0]).eql(['suricata-sensor-amsterdam']); - expect(hostNames[1]).eql(['suricata-sensor-san-francisco']); - expect(hostNames[2]).eql(['zeek-newyork-sha-aa8df15']); - expect(hostNames[3]).eql(['zeek-sensor-amsterdam']); - expect(hostNames[4]).eql(['zeek-sensor-san-francisco']); + expect(hostNames[0]).toEqual(['suricata-sensor-amsterdam']); + expect(hostNames[1]).toEqual(['suricata-sensor-san-francisco']); + expect(hostNames[2]).toEqual(['zeek-newyork-sha-aa8df15']); + expect(hostNames[3]).toEqual(['zeek-sensor-amsterdam']); + expect(hostNames[4]).toEqual(['zeek-sensor-san-francisco']); }); // github.com/elastic/kibana/issues/149920 @@ -538,9 +546,9 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(1); + expect(previewAlerts.length).toEqual(1); - expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).eql(['host-0', '127.0.0.2']); + expect(previewAlerts[0]._source?.['kibana.alert.new_terms']).toEqual(['host-0', '127.0.0.2']); }); describe('null values', () => { it('should not generate alerts with null values for single field', async () => { @@ -555,7 +563,7 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(0); + expect(previewAlerts.length).toEqual(0); }); it('should not generate alerts with null values for multiple fields', async () => { @@ -570,7 +578,7 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(0); + expect(previewAlerts.length).toEqual(0); }); }); @@ -587,7 +595,7 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId, size: 100 }); - expect(previewAlerts.length).eql(20); + expect(previewAlerts.length).toEqual(20); }); // There is a limit in ES for a number of emitted values in runtime field (100) @@ -605,7 +613,7 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - expect(previewAlerts.length).eql(100); + expect(previewAlerts.length).toEqual(100); }); // There is a limit in ES for a number of emitted values in runtime field (100) @@ -624,7 +632,7 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - expect(previewAlerts.length).eql(100); + expect(previewAlerts.length).toEqual(100); }); it('should not miss alerts if rule execution value combinations number is greater than 100', async () => { @@ -672,7 +680,7 @@ export default ({ getService }: FtrProviderContext) => { const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); // 10 alerts (with host.names a-[0-9]) should be generated - expect(previewAlerts.length).eql(10); + expect(previewAlerts.length).toEqual(10); }); it('should not miss alerts for high cardinality values in arrays, over 10.000 composite page size', async () => { @@ -731,7 +739,7 @@ export default ({ getService }: FtrProviderContext) => { const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); // only 1 alert should be generated - expect(previewAlerts.length).eql(1); + expect(previewAlerts.length).toEqual(1); }); it('should not miss alerts for high cardinality values in arrays, over 10.000 composite page size spread over multiple pages', async () => { @@ -817,7 +825,7 @@ export default ({ getService }: FtrProviderContext) => { const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); // only 4 alerts should be generated - expect(previewAlerts.length).eql(4); + expect(previewAlerts.length).toEqual(4); }); it('should not generate false positive alerts if rule historical window combinations overlap execution ones, which have more than 100', async () => { @@ -867,7 +875,7 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - expect(previewAlerts.length).eql(0); + expect(previewAlerts.length).toEqual(0); }); it('should not generate false positive alerts if rule historical window combinations overlap execution ones, which have precisely 100', async () => { @@ -911,7 +919,7 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId, size: 200 }); - expect(previewAlerts.length).eql(0); + expect(previewAlerts.length).toEqual(0); }); }); @@ -949,12 +957,12 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(2); + expect(previewAlerts.length).toEqual(2); const hostNames = previewAlerts .map((signal) => signal._source?.['kibana.alert.new_terms']) .sort(); - expect(hostNames[0]).eql(['host-3']); - expect(hostNames[1]).eql(['host-4']); + expect(hostNames[0]).toEqual(['host-3']); + expect(hostNames[1]).toEqual(['host-4']); }); }); @@ -989,14 +997,14 @@ export default ({ getService }: FtrProviderContext) => { }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts.length).eql(4); + expect(previewAlerts.length).toEqual(4); const hostNames = previewAlerts .map((signal) => signal._source?.['kibana.alert.new_terms']) .sort(); - expect(hostNames[0]).eql(['suricata-sensor-amsterdam']); - expect(hostNames[1]).eql(['suricata-sensor-san-francisco']); - expect(hostNames[2]).eql(['zeek-newyork-sha-aa8df15']); - expect(hostNames[3]).eql(['zeek-sensor-amsterdam']); + expect(hostNames[0]).toEqual(['suricata-sensor-amsterdam']); + expect(hostNames[1]).toEqual(['suricata-sensor-san-francisco']); + expect(hostNames[2]).toEqual(['zeek-newyork-sha-aa8df15']); + expect(hostNames[3]).toEqual(['zeek-sensor-amsterdam']); }); }); @@ -1014,11 +1022,11 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId, size: maxAlerts * 2 }); - expect(previewAlerts.length).eql(maxAlerts); + expect(previewAlerts.length).toEqual(maxAlerts); const processPids = previewAlerts .map((signal) => signal._source?.['kibana.alert.new_terms']) .sort(); - expect(processPids[0]).eql([1]); + expect(processPids[0]).toEqual([1]); }); describe('alerts should be be enriched', () => { @@ -1041,13 +1049,14 @@ export default ({ getService }: FtrProviderContext) => { const { previewId } = await previewRule({ supertest, rule }); const previewAlerts = await getPreviewAlerts({ es, previewId }); - expect(previewAlerts[0]?._source?.host?.risk?.calculated_level).to.eql('Low'); - expect(previewAlerts[0]?._source?.host?.risk?.calculated_score_norm).to.eql(23); + expect(previewAlerts[0]?._source?.host?.risk?.calculated_level).toEqual('Low'); + expect(previewAlerts[0]?._source?.host?.risk?.calculated_score_norm).toEqual(23); }); }); describe('with asset criticality', async () => { before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/security_solution/ecs_compliant'); await esArchiver.load('x-pack/test/functional/es_archives/asset_criticality'); await kibanaServer.uiSettings.update({ [ENABLE_ASSET_CRITICALITY_SETTING]: true, @@ -1055,23 +1064,54 @@ export default ({ getService }: FtrProviderContext) => { }); after(async () => { + await esArchiver.unload( + 'x-pack/test/functional/es_archives/security_solution/ecs_compliant' + ); await esArchiver.unload('x-pack/test/functional/es_archives/asset_criticality'); }); + const { indexListOfDocuments } = dataGeneratorFactory({ + es, + index: 'ecs_compliant', + log, + }); + it('should be enriched alert with criticality_level', async () => { + const id = uuidv4(); + const timestamp = '2020-10-28T06:45:00.000Z'; + + const firstExecutionDocuments = [ + { + host: { name: 'zeek-newyork-sha-aa8df15', ip: '127.0.0.5' }, + user: { name: 'root' }, + id, + '@timestamp': timestamp, + }, + ]; + + await indexListOfDocuments([...firstExecutionDocuments]); + const rule: NewTermsRuleCreateProps = { ...getCreateNewTermsRulesSchemaMock('rule-1', true), new_terms_fields: ['host.name'], - from: '2019-02-19T20:42:00.000Z', - history_window_start: '2019-01-19T20:42:00.000Z', + query: `id: "${id}"`, + index: ['ecs_compliant'], + history_window_start: '2019-10-13T05:00:04.000Z', + from: 'now-35m', + interval: '30m', }; - const { previewId } = await previewRule({ supertest, rule }); + const { previewId } = await previewRule({ + supertest, + rule, + timeframeEnd: new Date('2020-10-28T07:00:00.000Z'), + }); const previewAlerts = await getPreviewAlerts({ es, previewId }); + expect(previewAlerts.length).toBe(1); const fullAlert = previewAlerts[0]._source; - expect(fullAlert?.['host.asset.criticality']).to.eql('medium_impact'); - expect(fullAlert?.['user.asset.criticality']).to.eql('extreme_impact'); + expect(fullAlert?.['host.asset.criticality']).toBe('medium_impact'); + expect(fullAlert?.['user.asset.criticality']).toBe('extreme_impact'); }); }); }); From 63ceab2376cef3e79d811831bb846c53cf4b83d2 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Tue, 18 Jun 2024 12:54:03 -0400 Subject: [PATCH 044/123] feat(slo): Improve permission check on SLO pages (#182609) --- .../slo/slo_permissions_callout/index.tsx | 97 ++++++++++ .../hooks/use_fetch_global_diagnosis.ts | 10 +- .../slo/public/hooks/use_fetch_slo_list.ts | 1 + .../slo/public/hooks/use_permissions.test.ts | 169 ++++++++++++++++++ .../slo/public/hooks/use_permissions.ts | 43 +++++ .../slo_details/components/header_control.tsx | 16 +- .../pages/slo_details/slo_details.test.tsx | 36 +++- .../public/pages/slo_details/slo_details.tsx | 16 +- .../public/pages/slo_edit/slo_edit.test.tsx | 91 ++++++---- .../slo/public/pages/slo_edit/slo_edit.tsx | 27 +-- .../pages/slo_outdated_definitions/index.tsx | 29 ++- .../slos/components/common/create_slo_btn.tsx | 6 +- .../compact_view/slo_list_compact_view.tsx | 19 +- .../slos/components/slo_item_actions.tsx | 16 +- .../slo/public/pages/slos/slos.test.tsx | 32 +++- .../slo/public/pages/slos/slos.tsx | 16 +- .../pages/slos_welcome/slos_welcome.test.tsx | 64 ++++--- .../pages/slos_welcome/slos_welcome.tsx | 50 +++--- .../slo/server/services/get_diagnosis.ts | 2 +- 19 files changed, 556 insertions(+), 184 deletions(-) create mode 100644 x-pack/plugins/observability_solution/slo/public/components/slo/slo_permissions_callout/index.tsx create mode 100644 x-pack/plugins/observability_solution/slo/public/hooks/use_permissions.test.ts create mode 100644 x-pack/plugins/observability_solution/slo/public/hooks/use_permissions.ts diff --git a/x-pack/plugins/observability_solution/slo/public/components/slo/slo_permissions_callout/index.tsx b/x-pack/plugins/observability_solution/slo/public/components/slo/slo_permissions_callout/index.tsx new file mode 100644 index 00000000000000..720f31ccea3fa6 --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/components/slo/slo_permissions_callout/index.tsx @@ -0,0 +1,97 @@ +/* + * 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 { EuiCallOut, EuiSpacer, EuiLink, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; +import { usePermissions } from '../../../hooks/use_permissions'; + +export function SloPermissionsCallout() { + const { data: permissions, isLoading } = usePermissions(); + + if (isLoading) { + return null; + } + + if (permissions?.hasAllReadRequested || permissions?.hasAllWriteRequested) { + return null; + } + + return ( + <> + + + + + + + +
    +
  • + +
  • +
+
+ + + + +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ + + {i18n.translate('xpack.slo.permissionsCallout.readDocumentation', { + defaultMessage: 'Read the documentation for more details', + })} + +
+
+ + + ); +} diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_global_diagnosis.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_global_diagnosis.ts index 22862110910daa..df8ea83ed2aaa4 100644 --- a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_global_diagnosis.ts +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_global_diagnosis.ts @@ -19,11 +19,7 @@ interface SloGlobalDiagnosisResponse { } export interface UseFetchSloGlobalDiagnoseResponse { - isInitialLoading: boolean; isLoading: boolean; - isRefetching: boolean; - isSuccess: boolean; - isError: boolean; data: SloGlobalDiagnosisResponse | undefined; } @@ -33,7 +29,7 @@ export function useFetchSloGlobalDiagnosis(): UseFetchSloGlobalDiagnoseResponse notifications: { toasts }, } = useKibana().services; - const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ + const { isLoading, data } = useQuery({ queryKey: sloKeys.globalDiagnosis(), queryFn: async ({ signal }) => { try { @@ -65,9 +61,5 @@ export function useFetchSloGlobalDiagnosis(): UseFetchSloGlobalDiagnoseResponse return { data, isLoading, - isInitialLoading, - isRefetching, - isSuccess, - isError, }; } diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_list.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_list.ts index 289c8e5cbd4187..0e2bb39dab8781 100644 --- a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_list.ts +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_list.ts @@ -115,6 +115,7 @@ export function useFetchSloList({ if (String(error) === 'Error: Forbidden') { return false; } + return failureCount < 4; }, onSuccess: ({ results }: FindSLOResponse) => { diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_permissions.test.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_permissions.test.ts new file mode 100644 index 00000000000000..c9646c070dbbb2 --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_permissions.test.ts @@ -0,0 +1,169 @@ +/* + * 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 { sloFeatureId } from '@kbn/observability-shared-plugin/common'; +import { useKibana } from '../utils/kibana_react'; +import { useFetchSloGlobalDiagnosis } from './use_fetch_global_diagnosis'; +import { usePermissions } from './use_permissions'; + +jest.mock('../utils/kibana_react'); +jest.mock('./use_fetch_global_diagnosis'); + +const useKibanaMock = useKibana as jest.Mock; +const useFetchSloGlobalDiagnosisMock = useFetchSloGlobalDiagnosis as jest.Mock; + +describe('usePermissions', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('is loading until diagnosis is done', () => { + useKibanaMock.mockReturnValue({ + services: { + application: { capabilities: { [sloFeatureId]: { read: true, write: true } } }, + }, + }); + useFetchSloGlobalDiagnosisMock.mockReturnValue({ + data: undefined, + isLoading: true, + }); + + const { data, isLoading } = usePermissions(); + + expect(isLoading).toBe(true); + expect(data).toBe(undefined); + }); + + describe('hasAllReadRequested', () => { + it('returns hasAllReadRequested = true when both write capabilities and read privileges are true', () => { + useKibanaMock.mockReturnValue({ + services: { + application: { capabilities: { [sloFeatureId]: { read: true, write: false } } }, + }, + }); + useFetchSloGlobalDiagnosisMock.mockReturnValue({ + data: { + userPrivileges: { + read: { has_all_requested: true }, + write: { has_all_requested: false }, + }, + }, + isLoading: false, + }); + + const { data } = usePermissions(); + + expect(data?.hasAllReadRequested).toBe(true); + }); + + it('returns hasAllReadRequested = false when read capabilities is false and read privileges is true', () => { + useKibanaMock.mockReturnValue({ + services: { + application: { capabilities: { [sloFeatureId]: { read: false, write: false } } }, + }, + }); + useFetchSloGlobalDiagnosisMock.mockReturnValue({ + data: { + userPrivileges: { + read: { has_all_requested: true }, + write: { has_all_requested: false }, + }, + }, + isLoading: false, + }); + + const { data } = usePermissions(); + + expect(data?.hasAllReadRequested).toBe(false); + }); + + it('returns hasAllReadRequested = false when read capabilities is true and read privileges is false', () => { + useKibanaMock.mockReturnValue({ + services: { + application: { capabilities: { [sloFeatureId]: { read: true, write: false } } }, + }, + }); + useFetchSloGlobalDiagnosisMock.mockReturnValue({ + data: { + userPrivileges: { + read: { has_all_requested: false }, + write: { has_all_requested: false }, + }, + }, + isLoading: false, + }); + + const { data } = usePermissions(); + + expect(data?.hasAllReadRequested).toBe(false); + }); + }); + + describe('hasAllWriteRequested', () => { + it('returns hasAllWriteRequested = true when both write capabilities and write privileges are true', () => { + useKibanaMock.mockReturnValue({ + services: { + application: { capabilities: { [sloFeatureId]: { read: false, write: true } } }, + }, + }); + useFetchSloGlobalDiagnosisMock.mockReturnValue({ + data: { + userPrivileges: { + read: { has_all_requested: false }, + write: { has_all_requested: true }, + }, + }, + isLoading: false, + }); + + const { data } = usePermissions(); + + expect(data?.hasAllWriteRequested).toBe(true); + }); + + it('returns hasAllWriteRequested = false when write capabilities is false and write privileges is true', () => { + useKibanaMock.mockReturnValue({ + services: { + application: { capabilities: { [sloFeatureId]: { read: false, write: false } } }, + }, + }); + useFetchSloGlobalDiagnosisMock.mockReturnValue({ + data: { + userPrivileges: { + read: { has_all_requested: false }, + write: { has_all_requested: true }, + }, + }, + isLoading: false, + }); + + const { data } = usePermissions(); + + expect(data?.hasAllWriteRequested).toBe(false); + }); + + it('returns hasAllWriteRequested = false when write capabilities is true and write privileges is false', () => { + useKibanaMock.mockReturnValue({ + services: { + application: { capabilities: { [sloFeatureId]: { read: false, write: true } } }, + }, + }); + useFetchSloGlobalDiagnosisMock.mockReturnValue({ + data: { + userPrivileges: { + read: { has_all_requested: false }, + write: { has_all_requested: false }, + }, + }, + isLoading: false, + }); + + const { data } = usePermissions(); + + expect(data?.hasAllWriteRequested).toBe(false); + }); + }); +}); diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_permissions.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_permissions.ts new file mode 100644 index 00000000000000..6e380fbe1a33ea --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_permissions.ts @@ -0,0 +1,43 @@ +/* + * 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 { sloFeatureId } from '@kbn/observability-plugin/common'; +import { useKibana } from '../utils/kibana_react'; +import { useFetchSloGlobalDiagnosis } from './use_fetch_global_diagnosis'; + +export function usePermissions() { + const { + application: { capabilities }, + } = useKibana().services; + + const { data: globalDiagnosis, isLoading } = useFetchSloGlobalDiagnosis(); + + const hasRequiredReadCapabilities = !!capabilities[sloFeatureId].read ?? false; + const hasRequiredWriteCapabilities = !!capabilities[sloFeatureId].write ?? false; + + const hasRequiredReadPrivileges = + !!globalDiagnosis?.userPrivileges.read.has_all_requested ?? false; + const hasRequiredWritePrivileges = + !!globalDiagnosis?.userPrivileges.write.has_all_requested ?? false; + + return { + isLoading, + data: isLoading + ? undefined + : { + capabilities: { + read: hasRequiredReadCapabilities, + write: hasRequiredWriteCapabilities, + }, + privileges: { + read: hasRequiredReadPrivileges, + write: hasRequiredWritePrivileges, + }, + hasAllReadRequested: hasRequiredReadCapabilities && hasRequiredReadPrivileges, + hasAllWriteRequested: hasRequiredWriteCapabilities && hasRequiredWritePrivileges, + }, + }; +} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/header_control.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/header_control.tsx index 62399849224061..fb1e524e3e1700 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/header_control.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/header_control.tsx @@ -20,9 +20,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import { paths } from '../../../../common/locators/paths'; import { SloDeleteModal } from '../../../components/slo/delete_confirmation_modal/slo_delete_confirmation_modal'; import { SloResetConfirmationModal } from '../../../components/slo/reset_confirmation_modal/slo_reset_confirmation_modal'; -import { useCapabilities } from '../../../hooks/use_capabilities'; import { useCloneSlo } from '../../../hooks/use_clone_slo'; import { useFetchRulesForSlo } from '../../../hooks/use_fetch_rules_for_slo'; +import { usePermissions } from '../../../hooks/use_permissions'; import { useResetSlo } from '../../../hooks/use_reset_slo'; import { useKibana } from '../../../utils/kibana_react'; import { convertSliApmParamsToApmAppDeeplinkUrl } from '../../../utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url'; @@ -44,7 +44,7 @@ export function HeaderControl({ isLoading, slo }: Props) { } = useKibana().services; const hasApmReadCapabilities = capabilities.apm.show; - const { hasWriteCapabilities } = useCapabilities(); + const { data: permissions } = usePermissions(); const { isDeletingSlo, isResettingSlo, removeDeleteQueryParam, removeResetQueryParam } = useGetQueryParams(); @@ -198,7 +198,7 @@ export function HeaderControl({ isLoading, slo }: Props) { items={[ , , ({ ...jest.requireActual('react-router-dom'), @@ -42,7 +42,7 @@ jest.mock('react-router-dom', () => ({ jest.mock('@kbn/observability-shared-plugin/public'); jest.mock('../../utils/kibana_react'); jest.mock('../../hooks/use_license'); -jest.mock('../../hooks/use_capabilities'); +jest.mock('../../hooks/use_permissions'); jest.mock('../../hooks/use_fetch_active_alerts'); jest.mock('../../hooks/use_fetch_slo_details'); jest.mock('../../hooks/use_fetch_historical_summary'); @@ -53,7 +53,7 @@ jest.mock('../../hooks/use_delete_slo_instance'); const useKibanaMock = useKibana as jest.Mock; const useLicenseMock = useLicense as jest.Mock; -const useCapabilitiesMock = useCapabilities as jest.Mock; +const usePermissionsMock = usePermissions as jest.Mock; const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; const useFetchSloDetailsMock = useFetchSloDetails as jest.Mock; const useFetchHistoricalSummaryMock = useFetchHistoricalSummary as jest.Mock; @@ -134,7 +134,10 @@ describe('SLO Details Page', () => { beforeEach(() => { jest.clearAllMocks(); mockKibana(); - useCapabilitiesMock.mockReturnValue({ hasWriteCapabilities: true, hasReadCapabilities: true }); + usePermissionsMock.mockReturnValue({ + isLoading: false, + data: { hasAllReadRequested: true, hasAllWriteRequested: true }, + }); useCreateDataViewsMock.mockReturnValue({ dataView: { getName: () => 'dataview', getIndexPattern: () => '.dataview-index' }, }); @@ -151,7 +154,7 @@ describe('SLO Details Page', () => { }); describe('when the incorrect license is found', () => { - it('navigates to the SLO List page', async () => { + it('navigates to the SLO welcome page', async () => { const slo = buildSlo(); jest.spyOn(Router, 'useParams').mockReturnValue({ sloId: slo.id }); useFetchSloDetailsMock.mockReturnValue({ isLoading: false, data: slo }); @@ -159,7 +162,24 @@ describe('SLO Details Page', () => { render(); - expect(mockNavigate).toBeCalledWith(paths.slos); + expect(mockNavigate).toBeCalledWith(paths.slosWelcome); + }); + }); + + describe('when the user has not the requested read permissions ', () => { + it('navigates to the slos welcome page', async () => { + const slo = buildSlo(); + jest.spyOn(Router, 'useParams').mockReturnValue({ sloId: slo.id }); + useFetchSloDetailsMock.mockReturnValue({ isLoading: false, data: slo }); + useLicenseMock.mockReturnValue({ hasAtLeast: () => true }); + usePermissionsMock.mockReturnValue({ + isLoading: false, + data: { hasAllReadRequested: false, hasAllWriteRequested: false }, + }); + + render(); + + expect(mockNavigate).toBeCalledWith(paths.slosWelcome); }); }); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/slo_details.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/slo_details.tsx index 2c3cf109fa89f1..3da2e0f9911097 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/slo_details.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/slo_details.tsx @@ -21,6 +21,7 @@ import { AutoRefreshButton } from '../../components/slo/auto_refresh_button'; import { useAutoRefreshStorage } from '../../components/slo/auto_refresh_button/hooks/use_auto_refresh_storage'; import { useFetchSloDetails } from '../../hooks/use_fetch_slo_details'; import { useLicense } from '../../hooks/use_license'; +import { usePermissions } from '../../hooks/use_permissions'; import { usePluginContext } from '../../hooks/use_plugin_context'; import { useKibana } from '../../utils/kibana_react'; import PageNotFound from '../404'; @@ -41,6 +42,7 @@ export function SloDetailsPage() { const { ObservabilityPageTemplate } = usePluginContext(); const { hasAtLeast } = useLicense(); const hasRightLicense = hasAtLeast('platinum'); + const { data: permissions } = usePermissions(); const { sloId } = useParams(); const { instanceId: sloInstanceId, remoteName } = useGetQueryParams(); @@ -62,8 +64,6 @@ export function SloDetailsPage() { selectedTabId, }); - useBreadcrumbs(getBreadcrumbs(basePath, slo)); - useEffect(() => { if (!slo || !observabilityAIAssistant) { return; @@ -90,15 +90,19 @@ export function SloDetailsPage() { }); }, [observabilityAIAssistant, slo]); + useEffect(() => { + if (hasRightLicense === false || permissions?.hasAllReadRequested === false) { + navigateToUrl(basePath.prepend(paths.slosWelcome)); + } + }, [hasRightLicense, permissions, navigateToUrl, basePath]); + + useBreadcrumbs(getBreadcrumbs(basePath, slo)); + const isSloNotFound = !isLoading && slo === undefined; if (isSloNotFound) { return ; } - if (hasRightLicense === false) { - navigateToUrl(basePath.prepend(paths.slos)); - } - const isPerformingAction = isLoading || isDeleting; const handleToggleAutoRefresh = () => { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx index 5f6916720902b0..03838225d1618d 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx @@ -8,6 +8,8 @@ import { ILicense } from '@kbn/licensing-plugin/common/types'; import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; +import { useCreateRule, useFetchDataViews } from '@kbn/observability-plugin/public'; +import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public'; import { cleanup, fireEvent, waitFor } from '@testing-library/react'; import { createBrowserHistory } from 'history'; import React from 'react'; @@ -15,20 +17,18 @@ import Router from 'react-router-dom'; import { BehaviorSubject } from 'rxjs'; import { paths } from '../../../common/locators/paths'; import { buildSlo } from '../../data/slo/slo'; -import { useCapabilities } from '../../hooks/use_capabilities'; +import { useCreateDataView } from '../../hooks/use_create_data_view'; import { useCreateSlo } from '../../hooks/use_create_slo'; import { useFetchApmSuggestions } from '../../hooks/use_fetch_apm_suggestions'; +import { useFetchIndices } from '../../hooks/use_fetch_indices'; import { useFetchSloDetails } from '../../hooks/use_fetch_slo_details'; +import { usePermissions } from '../../hooks/use_permissions'; import { useUpdateSlo } from '../../hooks/use_update_slo'; -import { useCreateRule, useFetchDataViews } from '@kbn/observability-plugin/public'; -import { useCreateDataView } from '../../hooks/use_create_data_view'; -import { useFetchIndices } from '../../hooks/use_fetch_indices'; import { useKibana } from '../../utils/kibana_react'; import { kibanaStartMock } from '../../utils/kibana_react.mock'; import { render } from '../../utils/test_helper'; import { SLO_EDIT_FORM_DEFAULT_VALUES } from './constants'; import { SloEditPage } from './slo_edit'; -import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -36,14 +36,14 @@ jest.mock('react-router-dom', () => ({ })); jest.mock('@kbn/observability-shared-plugin/public'); +jest.mock('@kbn/observability-plugin/public'); jest.mock('../../hooks/use_fetch_indices'); jest.mock('../../hooks/use_create_data_view'); jest.mock('../../hooks/use_fetch_slo_details'); jest.mock('../../hooks/use_create_slo'); jest.mock('../../hooks/use_update_slo'); -jest.mock('@kbn/observability-plugin/public'); jest.mock('../../hooks/use_fetch_apm_suggestions'); -jest.mock('../../hooks/use_capabilities'); +jest.mock('../../hooks/use_permissions'); const mockUseKibanaReturnValue = kibanaStartMock.startContract(); @@ -54,13 +54,13 @@ jest.mock('../../utils/kibana_react', () => ({ const useKibanaMock = useKibana as jest.Mock; const useFetchIndicesMock = useFetchIndices as jest.Mock; const useFetchDataViewsMock = useFetchDataViews as jest.Mock; -const useCreateDataViewsMock = useCreateDataView as jest.Mock; +const useCreateDataViewMock = useCreateDataView as jest.Mock; const useFetchSloMock = useFetchSloDetails as jest.Mock; const useCreateSloMock = useCreateSlo as jest.Mock; const useUpdateSloMock = useUpdateSlo as jest.Mock; const useCreateRuleMock = useCreateRule as jest.Mock; const useFetchApmSuggestionsMock = useFetchApmSuggestions as jest.Mock; -const useCapabilitiesMock = useCapabilities as jest.Mock; +const usePermissionsMock = usePermissions as jest.Mock; const HeaderMenuPortalMock = HeaderMenuPortal as jest.Mock; HeaderMenuPortalMock.mockReturnValue(
Portal node
); @@ -77,12 +77,14 @@ const mockKibana = (license: ILicense | null = licenseMock) => { theme: {}, application: { navigateToUrl: mockNavigate, + capabilities: {}, }, charts: { theme: { useChartsBaseTheme: () => {}, }, }, + dataViewEditor: {}, data: { dataViews: { find: jest.fn().mockReturnValue([]), @@ -164,18 +166,20 @@ describe('SLO Edit Page', () => { data: [ { getName: () => 'dataview', - getIndexPattern: () => '.dataview-index', + getIndexPattern: () => 'some-index', getRuntimeMappings: jest.fn().mockReturnValue({}), }, ], }); - useCreateDataViewsMock.mockReturnValue({ + useCreateDataViewMock.mockReturnValue({ dataView: { getName: () => 'dataview', - getIndexPattern: () => '.dataview-index', + getIndexPattern: () => 'some-index', getRuntimeMappings: jest.fn().mockReturnValue({}), + fields: [{ name: 'custom_timestamp', type: 'date' }], }, + loading: false, }); useFetchIndicesMock.mockReturnValue({ @@ -203,16 +207,21 @@ describe('SLO Edit Page', () => { isError: false, mutateAsync: mockUpdate, }); + + usePermissionsMock.mockReturnValue({ + isLoading: false, + data: { + hasAllWriteRequested: true, + hasAllReadRequested: true, + }, + }); + licenseMock.hasAtLeast.mockReturnValue(true); }); afterEach(cleanup); describe('when the incorrect license is found', () => { beforeEach(() => { - useCapabilitiesMock.mockReturnValue({ - hasWriteCapabilities: true, - hasReadCapabilities: true, - }); licenseMock.hasAtLeast.mockReturnValue(false); }); @@ -232,10 +241,6 @@ describe('SLO Edit Page', () => { describe('when the license is null', () => { beforeEach(() => { - useCapabilitiesMock.mockReturnValue({ - hasWriteCapabilities: true, - hasReadCapabilities: true, - }); mockKibana(null); }); @@ -255,18 +260,17 @@ describe('SLO Edit Page', () => { describe('when the correct license is found', () => { beforeEach(() => { - useCapabilitiesMock.mockReturnValue({ - hasWriteCapabilities: true, - hasReadCapabilities: true, - }); licenseMock.hasAtLeast.mockReturnValue(true); }); describe('with no write permission', () => { beforeEach(() => { - useCapabilitiesMock.mockReturnValue({ - hasWriteCapabilities: false, - hasReadCapabilities: true, + usePermissionsMock.mockReturnValue({ + isLoading: false, + data: { + hasAllWriteRequested: false, + hasAllReadRequested: true, + }, }); }); @@ -284,6 +288,31 @@ describe('SLO Edit Page', () => { }); }); + describe('with no read permission', () => { + beforeEach(() => { + usePermissionsMock.mockReturnValue({ + isLoading: false, + data: { + hasAllWriteRequested: false, + hasAllReadRequested: false, + }, + }); + }); + + it('redirects to the slo welcome page', async () => { + jest.spyOn(Router, 'useParams').mockReturnValue({ sloId: '1234' }); + jest + .spyOn(Router, 'useLocation') + .mockReturnValue({ pathname: '/slos/1234/edit', search: '', state: '', hash: '' }); + + useFetchSloMock.mockReturnValue({ isLoading: false, data: undefined }); + + render(); + + expect(mockNavigate).toBeCalledWith(mockBasePathPrepend(paths.slosWelcome)); + }); + }); + describe('when no sloId route param is provided', () => { beforeEach(() => { useFetchSloMock.mockReturnValue({ isLoading: false, data: undefined }); @@ -345,7 +374,7 @@ describe('SLO Edit Page', () => { describe('when a sloId route param is provided', () => { it('prefills the form with the SLO values', async () => { const slo = buildSlo({ id: '123Foo' }); - useFetchSloMock.mockReturnValue({ isLoading: false, isInitialLoading: false, data: slo }); + useFetchSloMock.mockReturnValue({ isLoading: false, data: slo }); jest.spyOn(Router, 'useParams').mockReturnValue({ sloId: '123Foo' }); jest @@ -429,7 +458,6 @@ describe('SLO Edit Page', () => { describe('when submitting has completed successfully', () => { it('navigates to the SLO List page', async () => { const slo = buildSlo(); - jest.spyOn(Router, 'useParams').mockReturnValue({ sloId: '123' }); jest .spyOn(Router, 'useLocation') @@ -444,9 +472,8 @@ describe('SLO Edit Page', () => { await waitFor(() => { fireEvent.click(getByTestId('sloFormSubmitButton')); }); - await waitFor(() => { - expect(mockNavigate).toBeCalledWith(mockBasePathPrepend(paths.slos)); - }); + + expect(mockNavigate).toBeCalledWith(mockBasePathPrepend(paths.slos)); }); }); }); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx index 09f3b257e6542c..aa008838a8b3cd 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx @@ -7,16 +7,15 @@ import { i18n } from '@kbn/i18n'; import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public'; -import React from 'react'; +import React, { useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import { HeaderMenu } from '../../components/header_menu/header_menu'; -import { useKibana } from '../../utils/kibana_react'; import { paths } from '../../../common/locators/paths'; -import { useCapabilities } from '../../hooks/use_capabilities'; -import { useFetchSloGlobalDiagnosis } from '../../hooks/use_fetch_global_diagnosis'; +import { HeaderMenu } from '../../components/header_menu/header_menu'; import { useFetchSloDetails } from '../../hooks/use_fetch_slo_details'; import { useLicense } from '../../hooks/use_license'; +import { usePermissions } from '../../hooks/use_permissions'; import { usePluginContext } from '../../hooks/use_plugin_context'; +import { useKibana } from '../../utils/kibana_react'; import { SloEditForm } from './components/slo_edit_form'; export function SloEditPage() { @@ -24,11 +23,11 @@ export function SloEditPage() { application: { navigateToUrl }, http: { basePath }, } = useKibana().services; - const { hasWriteCapabilities } = useCapabilities(); - const { isError: hasErrorInGlobalDiagnosis } = useFetchSloGlobalDiagnosis(); + const { sloId } = useParams<{ sloId: string | undefined }>(); + + const { data: permissions } = usePermissions(); const { ObservabilityPageTemplate } = usePluginContext(); - const { sloId } = useParams<{ sloId: string | undefined }>(); const { hasAtLeast } = useLicense(); const hasRightLicense = hasAtLeast('platinum'); const { data: slo } = useFetchSloDetails({ sloId }); @@ -60,9 +59,15 @@ export function SloEditPage() { }, ]); - if (hasRightLicense === false || !hasWriteCapabilities || hasErrorInGlobalDiagnosis) { - navigateToUrl(basePath.prepend(paths.slos)); - } + useEffect(() => { + if (hasRightLicense === false || permissions?.hasAllReadRequested === false) { + navigateToUrl(basePath.prepend(paths.slosWelcome)); + } + + if (permissions?.hasAllWriteRequested === false) { + navigateToUrl(basePath.prepend(paths.slos)); + } + }, [hasRightLicense, permissions, navigateToUrl, basePath]); return ( {i18n.translate('xpack.slo.slosOutdatedDefinitions.sloPermissionsError', { @@ -96,7 +89,7 @@ export function SlosOutdatedDefinitions() { > - {!hasSlosAndHasPermissions ? ( + {!!errors ? ( errors ) : ( <> diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/common/create_slo_btn.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/common/create_slo_btn.tsx index 14701ef9e4f609..7add8debe165b7 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/common/create_slo_btn.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/common/create_slo_btn.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { useKibana } from '../../../../utils/kibana_react'; import { paths } from '../../../../../common/locators/paths'; -import { useCapabilities } from '../../../../hooks/use_capabilities'; +import { usePermissions } from '../../../../hooks/use_permissions'; export function CreateSloBtn() { const { @@ -18,7 +18,7 @@ export function CreateSloBtn() { http: { basePath }, } = useKibana().services; - const { hasWriteCapabilities } = useCapabilities(); + const { data: permissions } = usePermissions(); const handleClickCreateSlo = () => { navigateToUrl(basePath.prepend(paths.sloCreate)); @@ -27,7 +27,7 @@ export function CreateSloBtn() { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/compact_view/slo_list_compact_view.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/compact_view/slo_list_compact_view.tsx index d773d56ac47f8f..0d556c0546e1f4 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/compact_view/slo_list_compact_view.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/compact_view/slo_list_compact_view.tsx @@ -28,12 +28,12 @@ import { SloResetConfirmationModal } from '../../../../components/slo/reset_conf import { SloStatusBadge } from '../../../../components/slo/slo_status_badge'; import { SloActiveAlertsBadge } from '../../../../components/slo/slo_status_badge/slo_active_alerts_badge'; import { sloKeys } from '../../../../hooks/query_key_factory'; -import { useCapabilities } from '../../../../hooks/use_capabilities'; import { useCloneSlo } from '../../../../hooks/use_clone_slo'; import { useFetchActiveAlerts } from '../../../../hooks/use_fetch_active_alerts'; import { useFetchHistoricalSummary } from '../../../../hooks/use_fetch_historical_summary'; import { useFetchRulesForSlo } from '../../../../hooks/use_fetch_rules_for_slo'; import { useGetFilteredRuleTypes } from '../../../../hooks/use_get_filtered_rule_types'; +import { usePermissions } from '../../../../hooks/use_permissions'; import { useResetSlo } from '../../../../hooks/use_reset_slo'; import { useSpace } from '../../../../hooks/use_space'; import { useKibana } from '../../../../utils/kibana_react'; @@ -74,7 +74,7 @@ export function SloListCompactView({ sloList, loading, error }: Props) { (slo) => [slo.id, slo.instanceId ?? ALL_VALUE] as [string, string] ); - const { hasWriteCapabilities } = useCapabilities(); + const { data: permissions } = usePermissions(); const filteredRuleTypes = useGetFilteredRuleTypes(); const queryClient = useQueryClient(); @@ -173,7 +173,8 @@ export function SloListCompactView({ sloList, loading, error }: Props) { defaultMessage: 'Edit', }), 'data-test-subj': 'sloActionsEdit', - enabled: (slo) => (hasWriteCapabilities && !isRemote(slo)) || hasRemoteKibanaUrl(slo), + enabled: (slo) => + (permissions?.hasAllWriteRequested && !isRemote(slo)) || hasRemoteKibanaUrl(slo), onClick: (slo: SLOWithSummaryResponse) => { const remoteEditUrl = createRemoteSloEditUrl(slo, spaceId); if (!!remoteEditUrl) { @@ -193,7 +194,8 @@ export function SloListCompactView({ sloList, loading, error }: Props) { defaultMessage: 'Create new alert rule', }), 'data-test-subj': 'sloActionsCreateRule', - enabled: (slo: SLOWithSummaryResponse) => hasWriteCapabilities && !isRemote(slo), + enabled: (slo: SLOWithSummaryResponse) => + !!permissions?.hasAllWriteRequested && !isRemote(slo), onClick: (slo: SLOWithSummaryResponse) => { setSloToAddRule(slo); }, @@ -208,7 +210,8 @@ export function SloListCompactView({ sloList, loading, error }: Props) { defaultMessage: 'Manage rules', }), 'data-test-subj': 'sloActionsManageRules', - enabled: (slo: SLOWithSummaryResponse) => hasWriteCapabilities && !isRemote(slo), + enabled: (slo: SLOWithSummaryResponse) => + !!permissions?.hasAllWriteRequested && !isRemote(slo), onClick: (slo: SLOWithSummaryResponse) => { const locator = locators.get(rulesLocatorID); locator?.navigate({ params: { sloId: slo.id } }, { replace: false }); @@ -227,7 +230,7 @@ export function SloListCompactView({ sloList, loading, error }: Props) { }), 'data-test-subj': 'sloActionsClone', enabled: (slo: SLOWithSummaryResponse) => - (hasWriteCapabilities && !isRemote(slo)) || hasRemoteKibanaUrl(slo), + (permissions?.hasAllWriteRequested && !isRemote(slo)) || hasRemoteKibanaUrl(slo), onClick: (slo: SLOWithSummaryResponse) => { navigateToClone(slo); }, @@ -245,7 +248,7 @@ export function SloListCompactView({ sloList, loading, error }: Props) { }), 'data-test-subj': 'sloActionsDelete', enabled: (slo: SLOWithSummaryResponse) => - (hasWriteCapabilities && !isRemote(slo)) || hasRemoteKibanaUrl(slo), + (permissions?.hasAllWriteRequested && !isRemote(slo)) || hasRemoteKibanaUrl(slo), onClick: (slo: SLOWithSummaryResponse) => { const remoteDeleteUrl = createRemoteSloDeleteUrl(slo, spaceId); if (!!remoteDeleteUrl) { @@ -268,7 +271,7 @@ export function SloListCompactView({ sloList, loading, error }: Props) { }), 'data-test-subj': 'sloActionsReset', enabled: (slo: SLOWithSummaryResponse) => - (hasWriteCapabilities && !isRemote(slo)) || hasRemoteKibanaUrl(slo), + (permissions?.hasAllWriteRequested && !isRemote(slo)) || hasRemoteKibanaUrl(slo), onClick: (slo: SLOWithSummaryResponse) => { const remoteResetUrl = createRemoteSloResetUrl(slo, spaceId); if (!!remoteResetUrl) { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_item_actions.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_item_actions.tsx index a5de471bae883b..b3b6dbc645a2c3 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_item_actions.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_item_actions.tsx @@ -19,7 +19,7 @@ import { SLOWithSummaryResponse } from '@kbn/slo-schema'; import { Rule } from '@kbn/triggers-actions-ui-plugin/public'; import React from 'react'; import styled from 'styled-components'; -import { useCapabilities } from '../../../hooks/use_capabilities'; +import { usePermissions } from '../../../hooks/use_permissions'; import { useCloneSlo } from '../../../hooks/use_clone_slo'; import { BurnRateRuleParams } from '../../../typings'; import { useKibana } from '../../../utils/kibana_react'; @@ -76,7 +76,7 @@ export function SloItemActions({ } = useKibana().services; const executionContextName = executionContext.get().name; const isDashboardContext = executionContextName === 'dashboards'; - const { hasWriteCapabilities } = useCapabilities(); + const { data: permissions } = usePermissions(); const navigateToClone = useCloneSlo(); const { handleNavigateToRules, sloEditUrl, remoteDeleteUrl, remoteResetUrl, sloDetailsUrl } = @@ -182,7 +182,7 @@ export function SloItemActions({ , { selectedRemoteClusters: [], }, }); - useCapabilitiesMock.mockReturnValue({ hasWriteCapabilities: true, hasReadCapabilities: true }); + usePermissionsMock.mockReturnValue({ + isLoading: false, + data: { hasAllReadRequested: true, hasAllWriteRequested: true }, + }); jest .spyOn(Router, 'useLocation') .mockReturnValue({ pathname: '/slos', search: '', state: '', hash: '' }); @@ -175,6 +179,7 @@ describe('SLOs Page', () => { data: {}, }); }); + it('navigates to the SLOs Welcome Page', async () => { await act(async () => { render(); @@ -207,9 +212,28 @@ describe('SLOs Page', () => { }); }); - it('should have a create new SLO button', async () => { + it('navigates to the SLOs Welcome Page when the user has not the request read permissions', async () => { useFetchSloListMock.mockReturnValue({ isLoading: false, data: sloList }); + useFetchHistoricalSummaryMock.mockReturnValue({ + isLoading: false, + data: historicalSummaryData, + }); + usePermissionsMock.mockReturnValue({ + isLoading: false, + data: { hasAllReadRequested: false, hasAllWriteRequested: false }, + }); + await act(async () => { + render(); + }); + + await waitFor(() => { + expect(mockNavigate).toBeCalledWith(paths.slosWelcome); + }); + }); + + it('should have a create new SLO button', async () => { + useFetchSloListMock.mockReturnValue({ isLoading: false, data: sloList }); useFetchHistoricalSummaryMock.mockReturnValue({ isLoading: false, data: historicalSummaryData, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/slos.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/slos.tsx index fdb40e12ba4e27..30d519e61e38ff 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/slos.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/slos.tsx @@ -15,6 +15,7 @@ import { HeaderMenu } from '../../components/header_menu/header_menu'; import { SloOutdatedCallout } from '../../components/slo/slo_outdated_callout'; import { useFetchSloList } from '../../hooks/use_fetch_slo_list'; import { useLicense } from '../../hooks/use_license'; +import { usePermissions } from '../../hooks/use_permissions'; import { usePluginContext } from '../../hooks/use_plugin_context'; import { useKibana } from '../../utils/kibana_react'; import { CreateSloBtn } from './components/common/create_slo_btn'; @@ -31,14 +32,9 @@ export function SlosPage() { } = useKibana().services; const { ObservabilityPageTemplate } = usePluginContext(); const { hasAtLeast } = useLicense(); + const { data: permissions } = usePermissions(); - const { - isLoading, - isError, - data: sloList, - } = useFetchSloList({ - perPage: 0, - }); + const { isLoading, isError, data: sloList } = useFetchSloList({ perPage: 0 }); const { total } = sloList ?? { total: 0 }; useBreadcrumbs([ @@ -55,7 +51,11 @@ export function SlosPage() { if ((!isLoading && total === 0) || hasAtLeast('platinum') === false || isError) { navigateToUrl(basePath.prepend(paths.slosWelcome)); } - }, [basePath, hasAtLeast, isError, isLoading, navigateToUrl, total]); + + if (permissions?.hasAllReadRequested === false) { + navigateToUrl(basePath.prepend(paths.slosWelcome)); + } + }, [basePath, hasAtLeast, isError, isLoading, navigateToUrl, total, permissions]); return ( Portal node
); @@ -38,8 +36,7 @@ HeaderMenuPortalMock.mockReturnValue(
Portal node
); const useKibanaMock = useKibana as jest.Mock; const useLicenseMock = useLicense as jest.Mock; const useFetchSloListMock = useFetchSloList as jest.Mock; -const useCapabilitiesMock = useCapabilities as jest.Mock; -const useGlobalDiagnosisMock = useFetchSloGlobalDiagnosis as jest.Mock; +const usePermissionsMock = usePermissions as jest.Mock; const mockNavigate = jest.fn(); @@ -64,7 +61,6 @@ describe('SLOs Welcome Page', () => { beforeEach(() => { jest.clearAllMocks(); mockKibana(); - useCapabilitiesMock.mockReturnValue({ hasWriteCapabilities: true, hasReadCapabilities: true }); jest .spyOn(Router, 'useLocation') .mockReturnValue({ pathname: '/slos/welcome', search: '', state: '', hash: '' }); @@ -74,9 +70,11 @@ describe('SLOs Welcome Page', () => { it('renders the welcome message with subscription buttons', async () => { useFetchSloListMock.mockReturnValue({ isLoading: false, data: emptySloList }); useLicenseMock.mockReturnValue({ hasAtLeast: () => false }); - useGlobalDiagnosisMock.mockReturnValue({ + usePermissionsMock.mockReturnValue({ + isLoading: false, data: { - userPrivileges: { write: { has_all_requested: true }, read: { has_all_requested: true } }, + hasAllWriteRequested: true, + hasAllReadRequested: true, }, }); @@ -91,8 +89,12 @@ describe('SLOs Welcome Page', () => { describe('when the correct license is found', () => { beforeEach(() => { useLicenseMock.mockReturnValue({ hasAtLeast: () => true }); - useGlobalDiagnosisMock.mockReturnValue({ - isError: false, + usePermissionsMock.mockReturnValue({ + isLoading: false, + data: { + hasAllWriteRequested: true, + hasAllReadRequested: true, + }, }); }); @@ -102,9 +104,12 @@ describe('SLOs Welcome Page', () => { }); it('disables the create slo button when no write capabilities', async () => { - useCapabilitiesMock.mockReturnValue({ - hasWriteCapabilities: false, - hasReadCapabilities: true, + usePermissionsMock.mockReturnValue({ + isLoading: false, + data: { + hasAllWriteRequested: false, + hasAllReadRequested: true, + }, }); render(); @@ -117,16 +122,11 @@ describe('SLOs Welcome Page', () => { }); it('disables the create slo button when no cluster permissions capabilities', async () => { - useCapabilitiesMock.mockReturnValue({ - hasWriteCapabilities: true, - hasReadCapabilities: true, - }); - useGlobalDiagnosisMock.mockReturnValue({ + usePermissionsMock.mockReturnValue({ + isLoading: false, data: { - userPrivileges: { - write: { has_all_requested: false }, - read: { has_all_requested: true }, - }, + hasAllWriteRequested: false, + hasAllReadRequested: true, }, }); @@ -138,12 +138,11 @@ describe('SLOs Welcome Page', () => { }); it('should display the welcome message with a Create new SLO button which should navigate to the SLO Creation page', async () => { - useGlobalDiagnosisMock.mockReturnValue({ + usePermissionsMock.mockReturnValue({ + isLoading: false, data: { - userPrivileges: { - write: { has_all_requested: true }, - read: { has_all_requested: true }, - }, + hasAllWriteRequested: true, + hasAllReadRequested: true, }, }); @@ -163,12 +162,11 @@ describe('SLOs Welcome Page', () => { describe('when loading is done and results are found', () => { beforeEach(() => { useFetchSloListMock.mockReturnValue({ isLoading: false, data: sloList }); - useGlobalDiagnosisMock.mockReturnValue({ + usePermissionsMock.mockReturnValue({ + isLoading: false, data: { - userPrivileges: { - write: { has_all_requested: true }, - read: { has_all_requested: true }, - }, + hasAllWriteRequested: true, + hasAllReadRequested: true, }, }); }); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos_welcome/slos_welcome.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos_welcome/slos_welcome.tsx index 53b08809ecc6a6..fc03009beb72e4 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos_welcome/slos_welcome.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos_welcome/slos_welcome.tsx @@ -5,65 +5,61 @@ * 2.0. */ -import React, { useEffect } from 'react'; import { - EuiPageTemplate, EuiButton, - EuiTitle, - EuiLink, - EuiImage, - EuiSpacer, EuiFlexGroup, EuiFlexItem, + EuiImage, + EuiLink, + EuiPageTemplate, + EuiSpacer, + EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; - -import { useKibana } from '../../utils/kibana_react'; +import React, { useEffect } from 'react'; +import { paths } from '../../../common/locators/paths'; +import { HeaderMenu } from '../../components/header_menu/header_menu'; +import { SloOutdatedCallout } from '../../components/slo/slo_outdated_callout'; +import { SloPermissionsCallout } from '../../components/slo/slo_permissions_callout'; +import { useFetchSloList } from '../../hooks/use_fetch_slo_list'; import { useLicense } from '../../hooks/use_license'; +import { usePermissions } from '../../hooks/use_permissions'; import { usePluginContext } from '../../hooks/use_plugin_context'; -import { useCapabilities } from '../../hooks/use_capabilities'; -import { useFetchSloList } from '../../hooks/use_fetch_slo_list'; -import { paths } from '../../../common/locators/paths'; +import { useKibana } from '../../utils/kibana_react'; import illustration from './assets/illustration.svg'; -import { useFetchSloGlobalDiagnosis } from '../../hooks/use_fetch_global_diagnosis'; -import { SloOutdatedCallout } from '../../components/slo/slo_outdated_callout'; -import { HeaderMenu } from '../../components/header_menu/header_menu'; export function SlosWelcomePage() { const { application: { navigateToUrl }, http: { basePath }, } = useKibana().services; - const { hasWriteCapabilities } = useCapabilities(); - const { data: globalDiagnosis } = useFetchSloGlobalDiagnosis(); - const { ObservabilityPageTemplate } = usePluginContext(); + const { ObservabilityPageTemplate } = usePluginContext(); + const { data: permissions } = usePermissions(); const { hasAtLeast } = useLicense(); const hasRightLicense = hasAtLeast('platinum'); - const { isLoading, data: sloList } = useFetchSloList(); + const { data: sloList } = useFetchSloList(); const { total } = sloList ?? { total: 0 }; - const hasRequiredWritePrivileges = !!globalDiagnosis?.userPrivileges.write.has_all_requested; - const hasRequiredReadPrivileges = !!globalDiagnosis?.userPrivileges.read.has_all_requested; + const hasSlosAndPermissions = + total > 0 && hasRightLicense && permissions?.hasAllReadRequested === true; const handleClickCreateSlo = () => { navigateToUrl(basePath.prepend(paths.sloCreate)); }; - const hasSlosAndHasPermissions = - total > 0 && hasAtLeast('platinum') === true && hasRequiredReadPrivileges; - useEffect(() => { - if (hasSlosAndHasPermissions) { + if (hasSlosAndPermissions) { navigateToUrl(basePath.prepend(paths.slos)); } - }, [basePath, hasSlosAndHasPermissions, navigateToUrl]); + }, [basePath, navigateToUrl, hasSlosAndPermissions]); - return hasSlosAndHasPermissions || isLoading ? null : ( + return ( + @@ -117,7 +113,7 @@ export function SlosWelcomePage() { fill color="primary" onClick={handleClickCreateSlo} - disabled={!hasWriteCapabilities || !hasRequiredWritePrivileges} + disabled={!permissions?.hasAllWriteRequested} > {i18n.translate('xpack.slo.sloList.welcomePrompt.buttonLabel', { defaultMessage: 'Create SLO', diff --git a/x-pack/plugins/observability_solution/slo/server/services/get_diagnosis.ts b/x-pack/plugins/observability_solution/slo/server/services/get_diagnosis.ts index 697d3ceb560df0..38c183316a5911 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/get_diagnosis.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/get_diagnosis.ts @@ -14,7 +14,7 @@ export async function getGlobalDiagnosis( ) { const licenseInfo = licensing.license.toJSON(); const userWritePrivileges = await esClient.security.hasPrivileges({ - cluster: ['manage_transform'], + cluster: ['manage_transform', 'manage_ingest_pipelines'], index: [{ names: '.slo-*', privileges: ['all'] }], }); const userReadPrivileges = await esClient.security.hasPrivileges({ From 172163352761eb6edf870df79cdd0adf9c292123 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 18 Jun 2024 10:10:43 -0700 Subject: [PATCH 045/123] [HTTP/OAS] Add tags and descriptions for uptime setting APIs (#184268) --- .../server/legacy_uptime/routes/uptime_route_wrapper.ts | 6 +++++- .../uptime/server/legacy_uptime/uptime_server.ts | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/uptime_route_wrapper.ts b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/uptime_route_wrapper.ts index 5beaa563790e83..2590db8524105e 100644 --- a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/uptime_route_wrapper.ts +++ b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/uptime_route_wrapper.ts @@ -12,7 +12,11 @@ import { UptimeEsClient } from '../lib/lib'; export const uptimeRouteWrapper: UMKibanaRouteWrapper = (uptimeRoute, server) => ({ ...uptimeRoute, options: { - tags: ['access:uptime-read', ...(uptimeRoute?.writeAccess ? ['access:uptime-write'] : [])], + tags: [ + 'oas-tag:uptime', + 'access:uptime-read', + ...(uptimeRoute?.writeAccess ? ['access:uptime-write'] : []), + ], }, handler: async (context, request, response) => { const coreContext = await context.core; diff --git a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/uptime_server.ts b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/uptime_server.ts index 0c417a6e061e64..b8a9b56c2a9097 100644 --- a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/uptime_server.ts +++ b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/uptime_server.ts @@ -89,6 +89,7 @@ export const initUptimeServer = ( router.versioned .get({ access: 'public', + description: `Get uptime settings`, path: routeDefinition.path, options: { tags: options?.tags, @@ -115,6 +116,7 @@ export const initUptimeServer = ( router.versioned .put({ access: 'public', + description: `Update uptime settings`, path: routeDefinition.path, options: { tags: options?.tags, From 7ee93179e3c0574c86957bbc06e47b69b797fb75 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 18 Jun 2024 13:15:04 -0400 Subject: [PATCH 046/123] [Fleet] Add global data tags telemetry (#186390) --- .../fleet/server/collectors/agent_policies.ts | 20 +++++++++++++++++++ .../fleet_usage_telemetry.test.ts | 10 ++++++++++ .../services/telemetry/fleet_usages_schema.ts | 13 ++++++++++++ 3 files changed, 43 insertions(+) diff --git a/x-pack/plugins/fleet/server/collectors/agent_policies.ts b/x-pack/plugins/fleet/server/collectors/agent_policies.ts index d70524e5f1e32a..5210e7f3b229de 100644 --- a/x-pack/plugins/fleet/server/collectors/agent_policies.ts +++ b/x-pack/plugins/fleet/server/collectors/agent_policies.ts @@ -18,6 +18,8 @@ import type { OutputSOAttributes, AgentPolicy } from '../types'; export interface AgentPoliciesUsage { count: number; output_types: string[]; + count_with_global_data_tags: number; + avg_number_global_data_tags_per_policy?: number; } export const getAgentPoliciesUsage = async ( @@ -52,8 +54,26 @@ export const getAgentPoliciesUsage = async ( }) ); + const [policiesWithGlobalDataTag, totalNumberOfGlobalDataTagFields] = agentPolicies.reduce( + ([policiesNumber, fieldsNumber], agentPolicy) => { + if (agentPolicy.attributes.global_data_tags?.length ?? 0 > 0) { + return [ + policiesNumber + 1, + fieldsNumber + (agentPolicy.attributes.global_data_tags?.length ?? 0), + ]; + } + return [policiesNumber, fieldsNumber]; + }, + [0, 0] + ); + return { count: totalAgentPolicies, output_types: Array.from(uniqueOutputTypes), + count_with_global_data_tags: policiesWithGlobalDataTag, + avg_number_global_data_tags_per_policy: + policiesWithGlobalDataTag > 0 + ? Math.round(totalNumberOfGlobalDataTagFields / policiesWithGlobalDataTag) + : undefined, }; }; diff --git a/x-pack/plugins/fleet/server/integration_tests/fleet_usage_telemetry.test.ts b/x-pack/plugins/fleet/server/integration_tests/fleet_usage_telemetry.test.ts index 3ee659793f53fa..77b3278bad39af 100644 --- a/x-pack/plugins/fleet/server/integration_tests/fleet_usage_telemetry.test.ts +++ b/x-pack/plugins/fleet/server/integration_tests/fleet_usage_telemetry.test.ts @@ -428,6 +428,10 @@ describe('fleet usage telemetry', () => { schema_version: '1.0.0', data_output_id: 'output2', monitoring_output_id: 'output3', + global_data_tags: [ + { name: 'test', value: 'test1' }, + { name: 'test2', value: 'test2' }, + ], }, { id: 'policy2' } ); @@ -446,6 +450,10 @@ describe('fleet usage telemetry', () => { schema_version: '1.0.0', data_output_id: 'output4', monitoring_output_id: 'output4', + global_data_tags: [ + { name: 'test', value: 'test1' }, + { name: 'test2', value: 'test2' }, + ], }, { id: 'policy3' } ); @@ -566,6 +574,8 @@ describe('fleet usage telemetry', () => { agent_policies: { count: 3, output_types: expect.arrayContaining(['elasticsearch', 'logstash', 'third_type']), + count_with_global_data_tags: 2, + avg_number_global_data_tags_per_policy: 2, }, agent_logs_panics_last_hour: [ { diff --git a/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts b/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts index 35138145a71418..1720470b65ad89 100644 --- a/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts +++ b/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts @@ -346,6 +346,19 @@ export const fleetUsagesSchema: RootSchema = { _meta: { description: 'Output types of agent policies' }, }, }, + count_with_global_data_tags: { + type: 'long', + _meta: { + description: 'Number of agent policies using global data tags', + }, + }, + avg_number_global_data_tags_per_policy: { + type: 'long', + _meta: { + description: + 'Average number of global data tags defined per agent policy (accross policies using global data tags)', + }, + }, }, }, agent_checkin_status: { From 3528d54e2749f964c0eca6b561098ca370d40a78 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 18 Jun 2024 12:17:33 -0500 Subject: [PATCH 047/123] [ci] Remove 8.13 (#186377) 8.14 is released. 8.13 tests do not need to run now. --- .../pipeline-resource-definitions/kibana-on-merge.yml | 2 +- versions.json | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml b/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml index 8952951a27a5b7..497968f39ad95b 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-on-merge.yml @@ -25,7 +25,7 @@ spec: REPORT_FAILED_TESTS_TO_GITHUB: 'true' ELASTIC_SLACK_NOTIFICATIONS_ENABLED: 'true' allow_rebuilds: true - branch_configuration: main 7.17 8.13 8.14 + branch_configuration: main 7.17 8.14 default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/on_merge.yml diff --git a/versions.json b/versions.json index 9240760ec44f4e..f43e07cfdf2e28 100644 --- a/versions.json +++ b/versions.json @@ -13,12 +13,6 @@ "currentMajor": true, "previousMinor": true }, - { - "version": "8.13.5", - "branch": "8.13", - "currentMajor": true, - "previousMinor": true - }, { "version": "7.17.23", "branch": "7.17", From 243ed27d1a7ebee50677210632293dd07fe80172 Mon Sep 17 00:00:00 2001 From: Gerard Soldevila Date: Tue, 18 Jun 2024 19:23:16 +0200 Subject: [PATCH 048/123] Remove IE check + banner (#186396) ## Summary Address https://github.com/elastic/kibana/issues/138089 --- .../src/chrome_service.tsx | 30 ------------------- .../translations/translations/fr-FR.json | 2 -- .../translations/translations/ja-JP.json | 2 -- .../translations/translations/zh-CN.json | 2 -- 4 files changed, 36 deletions(-) diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx index 15ccb7c6a55310..d2922b9a966116 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx @@ -11,7 +11,6 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { BehaviorSubject, combineLatest, merge, type Observable, of, ReplaySubject } from 'rxjs'; import { mergeMap, map, takeUntil, filter } from 'rxjs'; import { parse } from 'url'; -import { EuiLink } from '@elastic/eui'; import useObservable from 'react-use/lib/useObservable'; import type { CoreContext } from '@kbn/core-base-browser-internal'; @@ -314,14 +313,6 @@ export class ChromeService { projectNavigation.setProjectName(projectName); }; - const isIE = () => { - const ua = window.navigator.userAgent; - const msie = ua.indexOf('MSIE '); // IE 10 or older - const trident = ua.indexOf('Trident/'); // IE 11 - - return msie > 0 || trident > 0; - }; - if (!this.params.browserSupportsCsp && injectedMetadata.getCspConfig().warnLegacyBrowsers) { notifications.toasts.addWarning({ title: mountReactNode( @@ -333,27 +324,6 @@ export class ChromeService { }); } - if (isIE()) { - notifications.toasts.addWarning({ - title: mountReactNode( - - -
- ), - }} - /> - ), - }); - } - const getHeaderComponent = () => { const defaultChromeStyle = chromeStyleSubject$.getValue(); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 7305a2ca70a1d6..cf8a0222a03780 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -547,7 +547,6 @@ "controls.timeSlider.previousLabel": "Fenêtre temporelle précédente", "controls.timeSlider.settings.pinStart": "Épingler le début", "controls.timeSlider.settings.unpinStart": "Désépingler le début", - "core.chrome.browserDeprecationWarning": "La prise en charge d'Internet Explorer sera abandonnée dans les futures versions de ce logiciel. Veuillez consulter le site {link}.", "core.deprecations.deprecations.fetchFailedMessage": "Impossible d'extraire les informations de déclassement pour le plug-in {domainId}.", "core.deprecations.deprecations.fetchFailedTitle": "Impossible d'extraire les déclassements pour {domainId}", "core.deprecations.elasticsearchSSL.manualSteps1": "Ajoutez le paramètre \"{missingSetting}\" à kibana.yml.", @@ -678,7 +677,6 @@ "core.application.appNotFound.pageDescription": "Aucune application détectée pour cette URL. Revenez en arrière ou sélectionnez une application dans le menu.", "core.application.appNotFound.title": "Application introuvable", "core.application.appRenderError.defaultTitle": "Erreur d'application", - "core.chrome.browserDeprecationLink": "la matrice de prise en charge sur notre site web", "core.chrome.legacyBrowserWarning": "Votre navigateur ne satisfait pas aux exigences de sécurité de Kibana.", "core.deprecations.deprecations.fetchFailed.manualStepOneMessage": "Vérifiez le message d'erreur dans les logs de serveur Kibana.", "core.deprecations.elasticsearchUsername.manualSteps1": "Utilisez l'outil CLI elasticsearch-service-tokens afin de créer un jeton pour le compte de service \"elastic/kibana\".", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2c6f6ea67b15e4..c50d9b9b36b2f1 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -549,7 +549,6 @@ "controls.timeSlider.previousLabel": "前の時間ウィンドウ", "controls.timeSlider.settings.pinStart": "開始をピン留め", "controls.timeSlider.settings.unpinStart": "開始をピン留め解除", - "core.chrome.browserDeprecationWarning": "このソフトウェアの将来のバージョンでは、Internet Explorerのサポートが削除されます。{link}をご確認ください。", "core.deprecations.deprecations.fetchFailedMessage": "プラグイン{domainId}の廃止予定情報を取得できません。", "core.deprecations.deprecations.fetchFailedTitle": "{domainId}の廃止予定を取得できませんでした", "core.deprecations.elasticsearchSSL.manualSteps1": "\"{missingSetting}\"設定をkibana.ymlに追加します。", @@ -678,7 +677,6 @@ "core.application.appNotFound.pageDescription": "この URL にアプリケーションが見つかりませんでした。前の画面に戻るか、メニューからアプリを選択してみてください。", "core.application.appNotFound.title": "アプリケーションが見つかりません", "core.application.appRenderError.defaultTitle": "アプリケーションエラー", - "core.chrome.browserDeprecationLink": "Web サイトのサポートマトリックス", "core.chrome.legacyBrowserWarning": "ご使用のブラウザが Kibana のセキュリティ要件を満たしていません。", "core.deprecations.deprecations.fetchFailed.manualStepOneMessage": "エラーメッセージについては、Kibanaサーバーログを確認してください。", "core.deprecations.elasticsearchUsername.manualSteps1": "elasticsearch-service-tokens CLIツールを使用して、「elastic/kibana」サービスアカウントの新しいサービスアカウントトークンを作成します。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 66f2bb582b4beb..cbfe1c3c90544c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -549,7 +549,6 @@ "controls.timeSlider.previousLabel": "上一时间窗口", "controls.timeSlider.settings.pinStart": "固定开始屏幕", "controls.timeSlider.settings.unpinStart": "取消固定开始屏幕", - "core.chrome.browserDeprecationWarning": "本软件的未来版本将放弃对 Internet Explorer 的支持,请查看{link}。", "core.deprecations.deprecations.fetchFailedMessage": "无法提取插件 {domainId} 的弃用信息。", "core.deprecations.deprecations.fetchFailedTitle": "无法提取 {domainId} 的弃用信息", "core.deprecations.elasticsearchSSL.manualSteps1": "将“{missingSetting}”设置添加到 kibana.yml。", @@ -680,7 +679,6 @@ "core.application.appNotFound.pageDescription": "在此 URL 未找到任何应用程序。尝试返回或从菜单中选择应用。", "core.application.appNotFound.title": "未找到应用程序", "core.application.appRenderError.defaultTitle": "应用程序错误", - "core.chrome.browserDeprecationLink": "我们网站上的支持矩阵", "core.chrome.legacyBrowserWarning": "您的浏览器不满足 Kibana 的安全要求。", "core.deprecations.deprecations.fetchFailed.manualStepOneMessage": "请在 Kibana 服务器日志中查看错误消息。", "core.deprecations.elasticsearchUsername.manualSteps1": "使用 elasticsearch-service-tokens CLI 工具为“elastic/kibana”服务帐户创建新的服务帐户令牌。", From dde8ef93bb793d973522a67e67997fe09606cd51 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 18 Jun 2024 10:25:34 -0700 Subject: [PATCH 049/123] [OAS] Edits OpenAPI documents for machine learning sync API (#186318) --- x-pack/plugins/ml/common/openapi/ml_apis.yaml | 23 ++++++++++--------- .../ml/common/openapi/ml_apis_serverless.yaml | 19 ++++++++------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/ml/common/openapi/ml_apis.yaml b/x-pack/plugins/ml/common/openapi/ml_apis.yaml index 9f2a7de4981844..d2854d049098ec 100644 --- a/x-pack/plugins/ml/common/openapi/ml_apis.yaml +++ b/x-pack/plugins/ml/common/openapi/ml_apis.yaml @@ -1,8 +1,8 @@ -openapi: 3.1.0 +openapi: 3.0.3 info: title: Machine learning APIs description: Kibana APIs for the machine learning feature - version: "1.0.2" + version: "1.0.1" license: name: Elastic License 2.0 url: https://www.elastic.co/licensing/elastic-license @@ -14,8 +14,11 @@ servers: paths: /api/ml/saved_objects/sync: get: - summary: Synchronizes Kibana saved objects for machine learning jobs and trained models. - description: This API runs automatically when you start Kibana and periodically thereafter. + summary: Sync saved objects in the default space + description: > + Synchronizes Kibana saved objects for machine learning jobs and trained models in the default space. + You must have `all` privileges for the **Machine Learning** feature in the **Analytics** section of the Kibana feature privileges. + This API runs automatically when you start Kibana and periodically thereafter. operationId: mlSync tags: - ml @@ -40,8 +43,9 @@ paths: /s/{spaceId}/api/ml/saved_objects/sync: get: - summary: Synchronizes Kibana saved objects for machine learning jobs and trained models. + summary: Sync saved objects description: > + Synchronizes Kibana saved objects for machine learning jobs and trained models. You must have `all` privileges for the **Machine Learning** feature in the **Analytics** section of the Kibana feature privileges. This API runs automatically when you start Kibana and periodically thereafter. operationId: mlSyncWithSpaceId @@ -82,8 +86,7 @@ components: required: false schema: type: boolean - examples: - - true + example: 'true' securitySchemes: basicAuth: type: http @@ -188,14 +191,12 @@ components: properties: error: type: string - examples: - - Unauthorized + example: Unauthorized message: type: string statusCode: type: integer - examples: - - 401 + example: 401 examples: mlSyncExample: summary: Two anomaly detection jobs required synchronization in this example. diff --git a/x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml b/x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml index 6ff44e29517e6d..d09b78c1155ae7 100644 --- a/x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml +++ b/x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml @@ -1,8 +1,8 @@ -openapi: 3.1.0 +openapi: 3.0.3 info: title: Machine learning APIs description: Kibana APIs for the machine learning feature - version: "1.0.2" + version: "1.0.1" license: name: Elastic License 2.0 url: https://www.elastic.co/licensing/elastic-license @@ -14,8 +14,10 @@ servers: paths: /api/ml/saved_objects/sync: get: - summary: Synchronizes Kibana saved objects for machine learning jobs and trained models. - description: This API runs automatically when you start Kibana and periodically thereafter. + summary: Sync machine learning saved objects + description: > + Synchronizes Kibana saved objects for machine learning jobs and trained models. + This API runs automatically when you start Kibana and periodically thereafter. operationId: mlSync tags: - ml @@ -46,8 +48,7 @@ components: required: false schema: type: boolean - examples: - - true + example: 'true' securitySchemes: apiKeyAuth: type: apiKey @@ -149,14 +150,12 @@ components: properties: error: type: string - examples: - - Unauthorized + example: Unauthorized message: type: string statusCode: type: integer - examples: - - 401 + example: 401 examples: mlSyncExample: summary: Two anomaly detection jobs required synchronization in this example. From e2a98cf965f61a5a2e23787869b214a5ba9061a5 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 18 Jun 2024 19:25:51 +0200 Subject: [PATCH 050/123] Add dashboard metadata to the info flyout (#185941) ## Summary Close https://github.com/elastic/kibana-team/issues/898 - Show createdAt, createdBy, updatedAt, updatedBy in info flyout. Add a bit of special handling for managed objects and when info is not available. - I had to extract some components into a separate package to use them in contentEditor package - tiny tweaks to column width and "no creator" state ![Screenshot 2024-06-12 at 17 01 45](https://github.com/elastic/kibana/assets/7784120/b2093c03-67a0-49a5-8a45-93d9e57813ca) **Unknown creator:** ![Screenshot 2024-06-12 at 17 01 53](https://github.com/elastic/kibana/assets/7784120/3e520f6a-9a19-455f-b564-571c3ad81b16) **For managed objects:** ![Screenshot 2024-06-12 at 17 01 57](https://github.com/elastic/kibana/assets/7784120/36ce1465-09a4-4936-a9f1-ca5794d45a7a) **Just created, no updates yet** ![Screenshot 2024-06-12 at 17 02 18](https://github.com/elastic/kibana/assets/7784120/1431210e-ce83-4409-ab99-6184b6f87d3a) --- .github/CODEOWNERS | 1 + package.json | 1 + .../src/components/activity_view.test.tsx | 113 +++++++++++ .../src/components/activity_view.tsx | 185 ++++++++++++++++++ .../src/components/editor_flyout_content.tsx | 7 +- .../editor_flyout_content_container.tsx | 1 + .../inspector_flyout_content.test.tsx | 17 ++ .../src/components/metadata_form.tsx | 16 +- .../src/open_content_editor.tsx | 8 +- .../content_editor/src/services.tsx | 16 +- .../content_editor/src/types.ts | 7 + .../content_editor/tsconfig.json | 8 +- .../table_list_view_common/index.ts | 2 + .../src/__jest__/created_by_filter.test.tsx | 2 +- .../src/__jest__/tests.helpers.tsx | 26 ++- .../src/components/user_filter_panel.tsx | 26 +-- .../src/components/user_missing_tip.tsx | 28 --- .../table_list_view_table/src/mocks.tsx | 2 - .../table_list_view_table/src/services.tsx | 76 +++---- .../src/table_list_view_table.tsx | 25 ++- .../table_list_view_table/tsconfig.json | 3 +- .../user_profiles/README.md | 3 + .../content-management/user_profiles/index.ts | 19 ++ .../user_profiles/jest.config.js | 13 ++ .../user_profiles/kibana.jsonc | 5 + .../user_profiles/package.json | 6 + .../user_profiles/src/components/index.ts | 11 ++ .../src/components/managed_avatar_tip.tsx | 12 +- .../src/components/user_avatar_tip.tsx | 12 +- .../src/components/user_missing_tip.tsx | 53 +++++ .../user_profiles/src/queries.ts | 36 ++++ .../user_profiles/src/services.tsx | 82 ++++++++ .../src/utils/batcher.test.tsx | 0 .../src/utils/batcher.ts | 0 .../user_profiles/tsconfig.json | 24 +++ .../use_dashboard_listing_table.test.tsx | 1 + .../hooks/use_dashboard_listing_table.tsx | 3 + tsconfig.base.json | 2 + yarn.lock | 4 + 39 files changed, 715 insertions(+), 141 deletions(-) create mode 100644 packages/content-management/content_editor/src/components/activity_view.test.tsx create mode 100644 packages/content-management/content_editor/src/components/activity_view.tsx delete mode 100644 packages/content-management/table_list_view_table/src/components/user_missing_tip.tsx create mode 100644 packages/content-management/user_profiles/README.md create mode 100644 packages/content-management/user_profiles/index.ts create mode 100644 packages/content-management/user_profiles/jest.config.js create mode 100644 packages/content-management/user_profiles/kibana.jsonc create mode 100644 packages/content-management/user_profiles/package.json create mode 100644 packages/content-management/user_profiles/src/components/index.ts rename packages/content-management/{table_list_view_table => user_profiles}/src/components/managed_avatar_tip.tsx (70%) rename packages/content-management/{table_list_view_table => user_profiles}/src/components/user_avatar_tip.tsx (72%) create mode 100644 packages/content-management/user_profiles/src/components/user_missing_tip.tsx create mode 100644 packages/content-management/user_profiles/src/queries.ts create mode 100644 packages/content-management/user_profiles/src/services.tsx rename packages/content-management/{table_list_view_table => user_profiles}/src/utils/batcher.test.tsx (100%) rename packages/content-management/{table_list_view_table => user_profiles}/src/utils/batcher.ts (100%) create mode 100644 packages/content-management/user_profiles/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a5fc58216acbfb..e519143df765df 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -101,6 +101,7 @@ packages/content-management/tabbed_table_list_view @elastic/appex-sharedux packages/content-management/table_list_view @elastic/appex-sharedux packages/content-management/table_list_view_common @elastic/appex-sharedux packages/content-management/table_list_view_table @elastic/appex-sharedux +packages/content-management/user_profiles @elastic/appex-sharedux packages/kbn-content-management-utils @elastic/kibana-data-discovery examples/controls_example @elastic/kibana-presentation src/plugins/controls @elastic/kibana-presentation diff --git a/package.json b/package.json index 0c50f51a82f2e5..989341509eb043 100644 --- a/package.json +++ b/package.json @@ -217,6 +217,7 @@ "@kbn/content-management-table-list-view": "link:packages/content-management/table_list_view", "@kbn/content-management-table-list-view-common": "link:packages/content-management/table_list_view_common", "@kbn/content-management-table-list-view-table": "link:packages/content-management/table_list_view_table", + "@kbn/content-management-user-profiles": "link:packages/content-management/user_profiles", "@kbn/content-management-utils": "link:packages/kbn-content-management-utils", "@kbn/controls-example-plugin": "link:examples/controls_example", "@kbn/controls-plugin": "link:src/plugins/controls", diff --git a/packages/content-management/content_editor/src/components/activity_view.test.tsx b/packages/content-management/content_editor/src/components/activity_view.test.tsx new file mode 100644 index 00000000000000..252591aba72ac3 --- /dev/null +++ b/packages/content-management/content_editor/src/components/activity_view.test.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 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 React from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; +import { UserProfilesProvider } from '@kbn/content-management-user-profiles'; +import { I18nProvider } from '@kbn/i18n-react'; + +import { ActivityView as ActivityViewComponent, ActivityViewProps } from './activity_view'; + +const mockGetUserProfile = jest.fn(async (uid: string) => ({ + uid, + enabled: true, + data: {}, + user: { username: uid, full_name: uid.toLocaleUpperCase() }, +})); + +const ActivityView = (props: ActivityViewProps) => { + return ( + + + + + + ); +}; + +test('should render activity view', () => { + render(); + + expect(screen.getByTestId('activityView')).toBeVisible(); + + expect(screen.getByTestId('createdByCard')).toHaveTextContent(/Unknown/); + expect(() => screen.getByTestId('updateByCard')).toThrow(); +}); + +test('should render creator card', async () => { + render(); + + await waitFor(() => { + const createdByCard = screen.getByTestId('createdByCard'); + expect(createdByCard).toHaveTextContent(/JOHN/); + expect(createdByCard).toHaveTextContent(/June 13/); + }); +}); + +test('should not render updater card when updatedAt matches createdAt', async () => { + render( + + ); + + expect(screen.getByTestId('createdByCard')).toBeVisible(); + expect(() => screen.getByTestId('updateByCard')).toThrow(); +}); + +test('should render updater card', async () => { + render( + + ); + + await waitFor(() => { + const createdByCard = screen.getByTestId('createdByCard'); + expect(createdByCard).toHaveTextContent(/JOHN/); + expect(createdByCard).toHaveTextContent(/June 13/); + }); + + await waitFor(() => { + const updatedByCard = screen.getByTestId('updatedByCard'); + expect(updatedByCard).toHaveTextContent(/PETE/); + expect(updatedByCard).toHaveTextContent(/June 14/); + }); +}); + +test('should handle managed objects', async () => { + render( + + ); + + await waitFor(() => { + const createdByCard = screen.getByTestId('createdByCard'); + expect(createdByCard).toHaveTextContent(/System/); + expect(createdByCard).toHaveTextContent(/June 13/); + }); + + const updatedByCard = screen.getByTestId('updatedByCard'); + expect(updatedByCard).toHaveTextContent(/System/); + expect(updatedByCard).toHaveTextContent(/June 14/); +}); diff --git a/packages/content-management/content_editor/src/components/activity_view.tsx b/packages/content-management/content_editor/src/components/activity_view.tsx new file mode 100644 index 00000000000000..eb413acb20e363 --- /dev/null +++ b/packages/content-management/content_editor/src/components/activity_view.tsx @@ -0,0 +1,185 @@ +/* + * 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 { + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiIconTip, + EuiPanel, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; +import { + UserAvatarTip, + useUserProfile, + NoUpdaterTip, + NoCreatorTip, + ManagedAvatarTip, +} from '@kbn/content-management-user-profiles'; +import { getUserDisplayName } from '@kbn/user-profile-components'; + +import { Item } from '../types'; + +export interface ActivityViewProps { + item: Pick; +} + +export const ActivityView = ({ item }: ActivityViewProps) => { + const showLastUpdated = Boolean(item.updatedAt && item.updatedAt !== item.createdAt); + + const UnknownUserLabel = ( + + ); + + const ManagedUserLabel = ( + <> + {' '} + + + ); + + return ( + + {' '} + + } + /> + + } + fullWidth + data-test-subj={'activityView'} + > + <> + + + + ) : item.managed ? ( + <>{ManagedUserLabel} + ) : ( + <> + {UnknownUserLabel} + + + ) + } + when={item.createdAt} + data-test-subj={'createdByCard'} + /> + + + {showLastUpdated && ( + + ) : item.managed ? ( + <>{ManagedUserLabel} + ) : ( + <> + {UnknownUserLabel} + + + ) + } + when={item.updatedAt} + data-test-subj={'updatedByCard'} + /> + )} + + + + + ); +}; + +const dateFormatter = new Intl.DateTimeFormat(i18n.getLocale(), { + dateStyle: 'long', + timeStyle: 'short', +}); + +const ActivityCard = ({ + what, + when, + who, + 'data-test-subj': dataTestSubj, +}: { + what: string; + who: React.ReactNode; + when?: string; + 'data-test-subj'?: string; +}) => { + return ( + + + {what} + + + + {who} + + {when && ( + <> + + + + + + )} + + ); +}; + +const UserLabel = ({ uid }: { uid: string }) => { + const userQuery = useUserProfile(uid); + + if (!userQuery.data) return null; + + return ( + <> + {getUserDisplayName(userQuery.data.user)} + + ); +}; diff --git a/packages/content-management/content_editor/src/components/editor_flyout_content.tsx b/packages/content-management/content_editor/src/components/editor_flyout_content.tsx index 007cc58c4e5add..a347dbb2c4d31a 100644 --- a/packages/content-management/content_editor/src/components/editor_flyout_content.tsx +++ b/packages/content-management/content_editor/src/components/editor_flyout_content.tsx @@ -28,6 +28,7 @@ import type { Item } from '../types'; import { MetadataForm } from './metadata_form'; import { useMetadataForm } from './use_metadata_form'; import type { CustomValidators } from './use_metadata_form'; +import { ActivityView } from './activity_view'; const getI18nTexts = ({ entityName }: { entityName: string }) => ({ saveButtonLabel: i18n.translate('contentManagement.contentEditor.saveButtonLabel', { @@ -55,6 +56,7 @@ export interface Props { }) => Promise; customValidators?: CustomValidators; onCancel: () => void; + showActivityView?: boolean; } const capitalize = (str: string) => `${str.charAt(0).toLocaleUpperCase()}${str.substring(1)}`; @@ -68,6 +70,7 @@ export const ContentEditorFlyoutContent: FC = ({ onSave, onCancel, customValidators, + showActivityView, }) => { const { euiTheme } = useEuiTheme(); const [isSubmitting, setIsSubmitting] = useState(false); @@ -147,7 +150,9 @@ export const ContentEditorFlyoutContent: FC = ({ tagsReferences={item.tags} TagList={TagList} TagSelector={TagSelector} - /> + > + {showActivityView && } + diff --git a/packages/content-management/content_editor/src/components/editor_flyout_content_container.tsx b/packages/content-management/content_editor/src/components/editor_flyout_content_container.tsx index c1a36406980f9b..18094bc04f0843 100644 --- a/packages/content-management/content_editor/src/components/editor_flyout_content_container.tsx +++ b/packages/content-management/content_editor/src/components/editor_flyout_content_container.tsx @@ -21,6 +21,7 @@ type CommonProps = Pick< | 'onCancel' | 'entityName' | 'customValidators' + | 'showActivityView' >; export type Props = CommonProps; diff --git a/packages/content-management/content_editor/src/components/inspector_flyout_content.test.tsx b/packages/content-management/content_editor/src/components/inspector_flyout_content.test.tsx index e4668d022d00dc..c543acedbae5b9 100644 --- a/packages/content-management/content_editor/src/components/inspector_flyout_content.test.tsx +++ b/packages/content-management/content_editor/src/components/inspector_flyout_content.test.tsx @@ -262,5 +262,22 @@ describe('', () => { tags: ['id-3', 'id-4'], // New selection }); }); + + test('should render activity view', async () => { + await act(async () => { + testBed = await setup({ showActivityView: true }); + }); + const { find, component } = testBed!; + + expect(find('activityView').exists()).toBe(true); + expect(find('activityView.createdByCard').exists()).toBe(true); + expect(find('activityView.updatedByCard').exists()).toBe(false); + + testBed.setProps({ + item: { ...savedObjectItem, updatedAt: '2021-01-01T00:00:00Z' }, + }); + component.update(); + expect(find('activityView.updatedByCard').exists()).toBe(true); + }); }); }); diff --git a/packages/content-management/content_editor/src/components/metadata_form.tsx b/packages/content-management/content_editor/src/components/metadata_form.tsx index 26b433edcd161a..c5db98dc2811bb 100644 --- a/packages/content-management/content_editor/src/components/metadata_form.tsx +++ b/packages/content-management/content_editor/src/components/metadata_form.tsx @@ -6,20 +6,20 @@ * Side Public License, v 1. */ -import React from 'react'; import type { FC } from 'react'; +import React from 'react'; import { i18n } from '@kbn/i18n'; import { + EuiFieldText, EuiForm, EuiFormRow, - EuiFieldText, - EuiTextArea, EuiSpacer, + EuiTextArea, EuiToolTip, } from '@elastic/eui'; import { ContentEditorFlyoutWarningsCallOut } from './editor_flyout_warnings'; -import type { MetadataFormState, Field } from './use_metadata_form'; +import type { Field, MetadataFormState } from './use_metadata_form'; import type { SavedObjectsReference, Services } from '../services'; interface Props { @@ -42,6 +42,7 @@ export const MetadataForm: FC = ({ TagSelector, isReadonly, readonlyReason, + children, }) => { const { title, @@ -137,6 +138,13 @@ export const MetadataForm: FC = ({ )} + + {children && ( + <> + + {children} + + )} ); }; diff --git a/packages/content-management/content_editor/src/open_content_editor.tsx b/packages/content-management/content_editor/src/open_content_editor.tsx index b9bace1b45994c..89b73991ba5d62 100644 --- a/packages/content-management/content_editor/src/open_content_editor.tsx +++ b/packages/content-management/content_editor/src/open_content_editor.tsx @@ -15,7 +15,13 @@ import type { ContentEditorFlyoutContentContainerProps } from './components'; export type OpenContentEditorParams = Pick< ContentEditorFlyoutContentContainerProps, - 'item' | 'onSave' | 'isReadonly' | 'readonlyReason' | 'entityName' | 'customValidators' + | 'item' + | 'onSave' + | 'isReadonly' + | 'readonlyReason' + | 'entityName' + | 'customValidators' + | 'showActivityView' >; export function useOpenContentEditor() { diff --git a/packages/content-management/content_editor/src/services.tsx b/packages/content-management/content_editor/src/services.tsx index 6edf58e45c846a..8a9938ff515617 100644 --- a/packages/content-management/content_editor/src/services.tsx +++ b/packages/content-management/content_editor/src/services.tsx @@ -8,6 +8,10 @@ import type { FC, PropsWithChildren, ReactNode } from 'react'; import React, { useCallback, useContext, useMemo } from 'react'; +import { + UserProfilesProvider, + useUserProfilesServices, +} from '@kbn/content-management-user-profiles'; import type { EuiComboBoxProps } from '@elastic/eui'; import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser'; @@ -130,11 +134,19 @@ export const ContentEditorKibanaProvider: FC< return Comp; }, [savedObjectsTagging?.ui.components.TagList]); + const userProfilesServices = useUserProfilesServices(); + const openFlyout = useCallback( (node: ReactNode, options: OverlayFlyoutOpenOptions) => { - return coreOpenFlyout(toMountPoint(node, startServices), options); + return coreOpenFlyout( + toMountPoint( + {node}, + startServices + ), + options + ); }, - [coreOpenFlyout, startServices] + [coreOpenFlyout, startServices, userProfilesServices] ); return ( diff --git a/packages/content-management/content_editor/src/types.ts b/packages/content-management/content_editor/src/types.ts index 02607aa70d8bb9..f54ad6b562ad8c 100644 --- a/packages/content-management/content_editor/src/types.ts +++ b/packages/content-management/content_editor/src/types.ts @@ -13,4 +13,11 @@ export interface Item { title: string; description?: string; tags: SavedObjectsReference[]; + + createdAt?: string; + createdBy?: string; + updatedAt?: string; + updatedBy?: string; + + managed?: boolean; } diff --git a/packages/content-management/content_editor/tsconfig.json b/packages/content-management/content_editor/tsconfig.json index 8a7a1c08ba74a4..b4f77e22f1f445 100644 --- a/packages/content-management/content_editor/tsconfig.json +++ b/packages/content-management/content_editor/tsconfig.json @@ -10,7 +10,9 @@ "react", "@kbn/ambient-ui-types", "@kbn/ambient-storybook-types", - "@emotion/react/types/css-prop" + "@emotion/react/types/css-prop", + "@testing-library/jest-dom", + "@testing-library/react" ] }, "include": [ @@ -26,7 +28,9 @@ "@kbn/core-i18n-browser", "@kbn/core-theme-browser", "@kbn/test-jest-helpers", - "@kbn/react-kibana-mount" + "@kbn/react-kibana-mount", + "@kbn/content-management-user-profiles", + "@kbn/user-profile-components" ], "exclude": [ "target/**/*" diff --git a/packages/content-management/table_list_view_common/index.ts b/packages/content-management/table_list_view_common/index.ts index fea9e6a918673b..4ca206e196f179 100644 --- a/packages/content-management/table_list_view_common/index.ts +++ b/packages/content-management/table_list_view_common/index.ts @@ -11,6 +11,8 @@ import type { SavedObjectsReference } from '@kbn/content-management-content-edit export interface UserContentCommonSchema { id: string; updatedAt: string; + updatedBy?: string; + createdAt?: string; createdBy?: string; managed?: boolean; references: SavedObjectsReference[]; diff --git a/packages/content-management/table_list_view_table/src/__jest__/created_by_filter.test.tsx b/packages/content-management/table_list_view_table/src/__jest__/created_by_filter.test.tsx index 5593bda387778e..bd68993b3f3ba1 100644 --- a/packages/content-management/table_list_view_table/src/__jest__/created_by_filter.test.tsx +++ b/packages/content-management/table_list_view_table/src/__jest__/created_by_filter.test.tsx @@ -147,7 +147,7 @@ describe('created_by filter', () => { // wait until first render expect(await screen.findByTestId('itemsInMemTable')).toBeVisible(); - // 5 items in the list + // 4 items in the list expect(screen.getAllByTestId(/userContentListingTitleLink/)).toHaveLength(4); userEvent.click(screen.getByTestId('userFilterPopoverButton')); diff --git a/packages/content-management/table_list_view_table/src/__jest__/tests.helpers.tsx b/packages/content-management/table_list_view_table/src/__jest__/tests.helpers.tsx index a1f35289c26ef3..d1f42f0d1d6b11 100644 --- a/packages/content-management/table_list_view_table/src/__jest__/tests.helpers.tsx +++ b/packages/content-management/table_list_view_table/src/__jest__/tests.helpers.tsx @@ -9,12 +9,13 @@ import React from 'react'; import type { ComponentType } from 'react'; import { from } from 'rxjs'; import { ContentEditorProvider } from '@kbn/content-management-content-editor'; +import { UserProfilesProvider, UserProfilesServices } from '@kbn/content-management-user-profiles'; import { TagList } from '../mocks'; import { TableListViewProvider, Services } from '../services'; -export const getMockServices = (overrides?: Partial) => { - const services: Services = { +export const getMockServices = (overrides?: Partial) => { + const services: Services & UserProfilesServices = { canEditAdvancedSettings: true, getListingLimitSettingsUrl: () => 'http://elastic.co', notifyError: () => undefined, @@ -25,24 +26,29 @@ export const getMockServices = (overrides?: Partial) => { itemHasTags: () => true, getTagManagementUrl: () => '', getTagIdsFromReferences: () => [], - bulkGetUserProfiles: jest.fn(() => Promise.resolve([])), - getUserProfile: jest.fn(), isTaggingEnabled: () => true, + bulkGetUserProfiles: async () => [], + getUserProfile: async () => ({ uid: '', enabled: true, data: {}, user: { username: '' } }), ...overrides, }; return services; }; -export function WithServices

(Comp: ComponentType

, overrides: Partial = {}) { +export function WithServices

( + Comp: ComponentType

, + overrides: Partial = {} +) { return (props: P) => { const services = getMockServices(overrides); return ( - undefined}> - - - - + + undefined}> + + + + + ); }; } diff --git a/packages/content-management/table_list_view_table/src/components/user_filter_panel.tsx b/packages/content-management/table_list_view_table/src/components/user_filter_panel.tsx index 2307f449b9c2d2..1f53678936065e 100644 --- a/packages/content-management/table_list_view_table/src/components/user_filter_panel.tsx +++ b/packages/content-management/table_list_view_table/src/components/user_filter_panel.tsx @@ -11,10 +11,8 @@ import React from 'react'; import { EuiFilterButton, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { UserProfile, UserProfilesPopover } from '@kbn/user-profile-components'; -import { useQuery, QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { useServices } from '../services'; -import { NoUsersTip } from './user_missing_tip'; +import { useUserProfiles, NoCreatorTip } from '@kbn/content-management-user-profiles'; interface Context { enabled: boolean; @@ -25,43 +23,29 @@ interface Context { } const UserFilterContext = React.createContext(null); -const queryClient = new QueryClient({ - defaultOptions: { queries: { retry: false, staleTime: 30 * 60 * 1000 } }, -}); export const UserFilterContextProvider: FC = ({ children, ...props }) => { if (!props.enabled) { return <>{children}; } - return ( - - {children} - - ); + return {children}; }; export const NULL_USER = 'no-user'; export const UserFilterPanel: FC<{}> = () => { - const { bulkGetUserProfiles } = useServices(); const { euiTheme } = useEuiTheme(); const componentContext = React.useContext(UserFilterContext); if (!componentContext) throw new Error('UserFilterPanel must be used within a UserFilterContextProvider'); - if (!bulkGetUserProfiles) - throw new Error('UserFilterPanel must be used with a bulkGetUserProfiles function'); const { onSelectedUsersChange, selectedUsers, showNoUserOption } = componentContext; const [isPopoverOpen, setPopoverOpen] = React.useState(false); const [searchTerm, setSearchTerm] = React.useState(''); - const query = useQuery({ - queryKey: ['user-filter-suggestions', componentContext.allUsers], - queryFn: () => bulkGetUserProfiles(componentContext.allUsers), - enabled: isPopoverOpen, - }); + const query = useUserProfiles(componentContext.allUsers, { enabled: isPopoverOpen }); const usersMap = React.useMemo(() => { if (!query.data) return {}; @@ -138,7 +122,7 @@ export const UserFilterPanel: FC<{}> = () => { id="contentManagement.tableList.listing.userFilter.emptyMessage" defaultMessage="None of the dashboards have creators" /> - {} + {}

), nullOptionLabel: i18n.translate( @@ -148,7 +132,7 @@ export const UserFilterPanel: FC<{}> = () => { } ), nullOptionProps: { - append: , + append: , }, clearButtonLabel: ( ( - - } - /> -); diff --git a/packages/content-management/table_list_view_table/src/mocks.tsx b/packages/content-management/table_list_view_table/src/mocks.tsx index a650d544aaecc6..f76954fd497a26 100644 --- a/packages/content-management/table_list_view_table/src/mocks.tsx +++ b/packages/content-management/table_list_view_table/src/mocks.tsx @@ -71,8 +71,6 @@ export const getStoryServices = (params: Params, action: ActionFn = () => {}) => itemHasTags: () => true, getTagManagementUrl: () => '', getTagIdsFromReferences: () => [], - bulkGetUserProfiles: () => Promise.resolve([]), - getUserProfile: jest.fn(), isTaggingEnabled: () => true, ...params, }; diff --git a/packages/content-management/table_list_view_table/src/services.tsx b/packages/content-management/table_list_view_table/src/services.tsx index 7be68fd28be910..5275dd35069cd7 100644 --- a/packages/content-management/table_list_view_table/src/services.tsx +++ b/packages/content-management/table_list_view_table/src/services.tsx @@ -20,11 +20,10 @@ import type { MountPoint, OverlayRef } from '@kbn/core-mount-utils-browser'; import type { OverlayFlyoutOpenOptions } from '@kbn/core-overlays-browser'; import type { ThemeServiceStart } from '@kbn/core-theme-browser'; import type { UserProfileServiceStart } from '@kbn/core-user-profile-browser'; -import type { UserProfile } from '@kbn/user-profile-components'; import type { FormattedRelative } from '@kbn/i18n-react'; import { toMountPoint } from '@kbn/react-kibana-mount'; import { RedirectAppLinksKibanaProvider } from '@kbn/shared-ux-link-redirect-app'; -import { createBatcher } from './utils/batcher'; +import { UserProfilesKibanaProvider } from '@kbn/content-management-user-profiles'; import { TAG_MANAGEMENT_APP_URL } from './constants'; import type { Tag } from './types'; @@ -69,9 +68,6 @@ export interface Services { /** Handler to return the url to navigate to the kibana tags management */ getTagManagementUrl: () => string; getTagIdsFromReferences: (references: SavedObjectsReference[]) => string[]; - /** resolve user profiles for the user filter and creator functionality */ - bulkGetUserProfiles: (uids: string[]) => Promise; - getUserProfile: (uid: string) => Promise; } const TableListViewContext = React.createContext(null); @@ -229,51 +225,35 @@ export const TableListViewKibanaProvider: FC< [getTagIdsFromReferences] ); - const bulkGetUserProfiles = useCallback<(userProfileIds: string[]) => Promise>( - async (uids: string[]) => { - if (uids.length === 0) return []; - - return core.userProfile.bulkGet({ uids: new Set(uids), dataPath: 'avatar' }); - }, - [core.userProfile] - ); - - const getUserProfile = useMemo(() => { - return createBatcher({ - fetcher: bulkGetUserProfiles, - resolver: (users, id) => users.find((u) => u.uid === id)!, - }).fetch; - }, [bulkGetUserProfiles]); - return ( - - - application.getUrlForApp('management', { - path: `/kibana/settings?query=savedObjects:listingLimit`, - }) - } - notifyError={(title, text) => { - notifications.toasts.addDanger({ title: toMountPoint(title, startServices), text }); - }} - searchQueryParser={searchQueryParser} - DateFormatterComp={(props) => } - currentAppId$={application.currentAppId$} - navigateToUrl={application.navigateToUrl} - isTaggingEnabled={() => Boolean(savedObjectsTagging)} - getTagList={getTagList} - TagList={TagList} - itemHasTags={itemHasTags} - getTagIdsFromReferences={getTagIdsFromReferences} - getTagManagementUrl={() => core.http.basePath.prepend(TAG_MANAGEMENT_APP_URL)} - bulkGetUserProfiles={bulkGetUserProfiles} - getUserProfile={getUserProfile} - > - {children} - - + + + + application.getUrlForApp('management', { + path: `/kibana/settings?query=savedObjects:listingLimit`, + }) + } + notifyError={(title, text) => { + notifications.toasts.addDanger({ title: toMountPoint(title, startServices), text }); + }} + searchQueryParser={searchQueryParser} + DateFormatterComp={(props) => } + currentAppId$={application.currentAppId$} + navigateToUrl={application.navigateToUrl} + isTaggingEnabled={() => Boolean(savedObjectsTagging)} + getTagList={getTagList} + TagList={TagList} + itemHasTags={itemHasTags} + getTagIdsFromReferences={getTagIdsFromReferences} + getTagManagementUrl={() => core.http.basePath.prepend(TAG_MANAGEMENT_APP_URL)} + > + {children} + + + ); }; diff --git a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx index 6cac7f7db88701..9e69c4e0f44345 100644 --- a/packages/content-management/table_list_view_table/src/table_list_view_table.tsx +++ b/packages/content-management/table_list_view_table/src/table_list_view_table.tsx @@ -27,6 +27,11 @@ import { FormattedMessage } from '@kbn/i18n-react'; import type { IHttpFetchError } from '@kbn/core-http-browser'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import { useOpenContentEditor } from '@kbn/content-management-content-editor'; +import { + UserAvatarTip, + ManagedAvatarTip, + NoCreatorTip, +} from '@kbn/content-management-user-profiles'; import type { OpenContentEditorParams, SavedObjectsReference, @@ -47,12 +52,12 @@ import { type SortColumnField, getInitialSorting, saveSorting } from './componen import { useTags } from './use_tags'; import { useInRouterContext, useUrlState } from './use_url_state'; import { RowActions, TableItemsRowActions } from './types'; -import { UserAvatarTip } from './components/user_avatar_tip'; -import { NoUsersTip } from './components/user_missing_tip'; -import { ManagedAvatarTip } from './components/managed_avatar_tip'; interface ContentEditorConfig - extends Pick { + extends Pick< + OpenContentEditorParams, + 'isReadonly' | 'onSave' | 'customValidators' | 'showActivityView' + > { enabled?: boolean; } @@ -506,6 +511,11 @@ function TableListViewTableComp({ title: item.attributes.title, description: item.attributes.description, tags, + createdAt: item.createdAt, + createdBy: item.createdBy, + updatedAt: item.updatedAt, + updatedBy: item.updatedBy, + managed: item.managed, }, entityName, ...contentEditor, @@ -575,7 +585,6 @@ function TableListViewTableComp({ {i18n.translate('contentManagement.tableList.createdByColumnTitle', { defaultMessage: 'Creator', })} - ), render: (field: string, record: { createdBy?: string; managed?: boolean }) => @@ -583,7 +592,9 @@ function TableListViewTableComp({ ) : record.managed ? ( - ) : null, + ) : ( + + ), sortable: false /* createdBy column is not sortable because it doesn't make sense to sort by id*/, width: '100px', @@ -601,7 +612,7 @@ function TableListViewTableComp({ ), sortable: true, - width: '120px', + width: '130px', }); } diff --git a/packages/content-management/table_list_view_table/tsconfig.json b/packages/content-management/table_list_view_table/tsconfig.json index 318c7ce382a9bd..09bf8256764d1e 100644 --- a/packages/content-management/table_list_view_table/tsconfig.json +++ b/packages/content-management/table_list_view_table/tsconfig.json @@ -33,7 +33,8 @@ "@kbn/content-management-table-list-view-common", "@kbn/user-profile-components", "@kbn/core-user-profile-browser", - "@kbn/react-kibana-mount" + "@kbn/react-kibana-mount", + "@kbn/content-management-user-profiles" ], "exclude": [ "target/**/*" diff --git a/packages/content-management/user_profiles/README.md b/packages/content-management/user_profiles/README.md new file mode 100644 index 00000000000000..e3559c9070f629 --- /dev/null +++ b/packages/content-management/user_profiles/README.md @@ -0,0 +1,3 @@ +# @kbn/content-management-user-profiles + +Shared user profile components for content management components. diff --git a/packages/content-management/user_profiles/index.ts b/packages/content-management/user_profiles/index.ts new file mode 100644 index 00000000000000..bce8d57baddcd4 --- /dev/null +++ b/packages/content-management/user_profiles/index.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 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 { UserAvatarTip, NoUpdaterTip, NoCreatorTip, ManagedAvatarTip } from './src/components'; + +export { useUserProfile, useUserProfiles } from './src/queries'; + +export { + UserProfilesKibanaProvider, + type UserProfilesKibanaDependencies, + UserProfilesProvider, + type UserProfilesServices, + useUserProfilesServices, +} from './src/services'; diff --git a/packages/content-management/user_profiles/jest.config.js b/packages/content-management/user_profiles/jest.config.js new file mode 100644 index 00000000000000..464585a8180552 --- /dev/null +++ b/packages/content-management/user_profiles/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/packages/content-management/user_profiles'], +}; diff --git a/packages/content-management/user_profiles/kibana.jsonc b/packages/content-management/user_profiles/kibana.jsonc new file mode 100644 index 00000000000000..6422efa40b631d --- /dev/null +++ b/packages/content-management/user_profiles/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/content-management-user-profiles", + "owner": "@elastic/appex-sharedux" +} diff --git a/packages/content-management/user_profiles/package.json b/packages/content-management/user_profiles/package.json new file mode 100644 index 00000000000000..bb5629d86ff0bd --- /dev/null +++ b/packages/content-management/user_profiles/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/content-management-user-profiles", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/content-management/user_profiles/src/components/index.ts b/packages/content-management/user_profiles/src/components/index.ts new file mode 100644 index 00000000000000..1f6e2116145b9b --- /dev/null +++ b/packages/content-management/user_profiles/src/components/index.ts @@ -0,0 +1,11 @@ +/* + * 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 { UserAvatarTip } from './user_avatar_tip'; +export { NoUpdaterTip, NoCreatorTip } from './user_missing_tip'; +export { ManagedAvatarTip } from './managed_avatar_tip'; diff --git a/packages/content-management/table_list_view_table/src/components/managed_avatar_tip.tsx b/packages/content-management/user_profiles/src/components/managed_avatar_tip.tsx similarity index 70% rename from packages/content-management/table_list_view_table/src/components/managed_avatar_tip.tsx rename to packages/content-management/user_profiles/src/components/managed_avatar_tip.tsx index 1453a5183e9c6b..02e22faa629fb0 100644 --- a/packages/content-management/table_list_view_table/src/components/managed_avatar_tip.tsx +++ b/packages/content-management/user_profiles/src/components/managed_avatar_tip.tsx @@ -10,10 +10,16 @@ import React from 'react'; import { EuiAvatar, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -export function ManagedAvatarTip({ entityName }: { entityName: string }) { +export function ManagedAvatarTip({ + entityName = i18n.translate('contentManagement.userProfiles.managedAvatarTip.defaultEntityName', { + defaultMessage: 'object', + }), +}: { + entityName?: string; +}) { return ( { - return getUserProfile(props.uid); - }, - { staleTime: Infinity } - ); + const query = useUserProfile(props.uid); if (query.data) { return ( diff --git a/packages/content-management/user_profiles/src/components/user_missing_tip.tsx b/packages/content-management/user_profiles/src/components/user_missing_tip.tsx new file mode 100644 index 00000000000000..758429b781537a --- /dev/null +++ b/packages/content-management/user_profiles/src/components/user_missing_tip.tsx @@ -0,0 +1,53 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n-react'; +import { EuiIconTip, IconType } from '@elastic/eui'; +import React from 'react'; + +export const NoCreatorTip = (props: { iconType?: IconType }) => ( + + } + {...props} + /> +); + +export const NoUpdaterTip = (props: { iconType?: string }) => ( + + } + {...props} + /> +); + +const NoUsersTip = ({ + iconType: type = 'questionInCircle', + ...props +}: { + content: React.ReactNode; + iconType?: IconType; +}) => ( + +); diff --git a/packages/content-management/user_profiles/src/queries.ts b/packages/content-management/user_profiles/src/queries.ts new file mode 100644 index 00000000000000..b238a5489d20cc --- /dev/null +++ b/packages/content-management/user_profiles/src/queries.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 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 { useQuery } from '@tanstack/react-query'; +import { useUserProfilesServices } from './services'; + +export const userProfileKeys = { + get: (uid: string) => ['user-profile', uid], + bulkGet: (uids: string[]) => ['user-profile', { uids }], +}; + +export const useUserProfile = (uid: string) => { + const { getUserProfile } = useUserProfilesServices(); + const query = useQuery( + userProfileKeys.get(uid), + async () => { + return getUserProfile(uid); + }, + { staleTime: Infinity } + ); + return query; +}; + +export const useUserProfiles = (uids: string[], opts?: { enabled?: boolean }) => { + const { bulkGetUserProfiles } = useUserProfilesServices(); + const query = useQuery({ + queryKey: userProfileKeys.bulkGet(uids), + queryFn: () => bulkGetUserProfiles(uids), + enabled: opts?.enabled ?? true, + }); + return query; +}; diff --git a/packages/content-management/user_profiles/src/services.tsx b/packages/content-management/user_profiles/src/services.tsx new file mode 100644 index 00000000000000..25ea8d4b5acda0 --- /dev/null +++ b/packages/content-management/user_profiles/src/services.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import type { UserProfileServiceStart } from '@kbn/core-user-profile-browser'; +import React, { FC, PropsWithChildren, useCallback, useContext, useMemo } from 'react'; +import type { UserProfile } from '@kbn/user-profile-components'; +import { createBatcher } from './utils/batcher'; + +export const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false, staleTime: 30 * 60 * 1000 } }, +}); + +export interface UserProfilesKibanaDependencies { + core: { + userProfile: { + bulkGet: UserProfileServiceStart['bulkGet']; + }; + }; +} + +export interface UserProfilesServices { + bulkGetUserProfiles: (uids: string[]) => Promise; + getUserProfile: (uid: string) => Promise; +} + +const UserProfilesContext = React.createContext(null); + +export const UserProfilesProvider: FC> = ({ + children, + ...services +}) => { + return ( + + {children} + + ); +}; + +export const UserProfilesKibanaProvider: FC> = ({ + children, + core, +}) => { + const bulkGetUserProfiles = useCallback<(userProfileIds: string[]) => Promise>( + async (uids: string[]) => { + if (uids.length === 0) return []; + + return core.userProfile.bulkGet({ uids: new Set(uids), dataPath: 'avatar' }); + }, + [core.userProfile] + ); + + const getUserProfile = useMemo(() => { + return createBatcher({ + fetcher: bulkGetUserProfiles, + resolver: (users, id) => users.find((u) => u.uid === id)!, + }).fetch; + }, [bulkGetUserProfiles]); + + return ( + + {children} + + ); +}; + +export function useUserProfilesServices() { + const context = useContext(UserProfilesContext); + + if (!context) { + throw new Error( + 'UserProfilesContext is missing. Ensure your component or React root is wrapped with ' + ); + } + + return context; +} diff --git a/packages/content-management/table_list_view_table/src/utils/batcher.test.tsx b/packages/content-management/user_profiles/src/utils/batcher.test.tsx similarity index 100% rename from packages/content-management/table_list_view_table/src/utils/batcher.test.tsx rename to packages/content-management/user_profiles/src/utils/batcher.test.tsx diff --git a/packages/content-management/table_list_view_table/src/utils/batcher.ts b/packages/content-management/user_profiles/src/utils/batcher.ts similarity index 100% rename from packages/content-management/table_list_view_table/src/utils/batcher.ts rename to packages/content-management/user_profiles/src/utils/batcher.ts diff --git a/packages/content-management/user_profiles/tsconfig.json b/packages/content-management/user_profiles/tsconfig.json new file mode 100644 index 00000000000000..de0aeff18778f7 --- /dev/null +++ b/packages/content-management/user_profiles/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/user-profile-components", + "@kbn/core-user-profile-browser", + "@kbn/i18n", + "@kbn/i18n-react", + ] +} diff --git a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.test.tsx b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.test.tsx index 2fc8c2d36ee0e0..b2493454d4da26 100644 --- a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.test.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.test.tsx @@ -154,6 +154,7 @@ describe('useDashboardListingTable', () => { onSave: expect.any(Function), isReadonly: false, customValidators: expect.any(Object), + showActivityView: true, }, createdByEnabled: true, }; diff --git a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx index 83638b01b190ee..659e5e43930ea2 100644 --- a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx @@ -42,7 +42,9 @@ const toTableListViewSavedObject = (hit: DashboardItem): DashboardSavedObjectUse type: 'dashboard', id: hit.id, updatedAt: hit.updatedAt!, + createdAt: hit.createdAt, createdBy: hit.createdBy, + updatedBy: hit.updatedBy, references: hit.references, managed: hit.managed, attributes: { @@ -280,6 +282,7 @@ export const useDashboardListingTable = ({ isReadonly: !showWriteControls, onSave: updateItemMeta, customValidators: contentEditorValidators, + showActivityView: true, }, createItem: !showWriteControls || !showCreateDashboardButton ? undefined : createItem, deleteItems: !showWriteControls ? undefined : deleteItems, diff --git a/tsconfig.base.json b/tsconfig.base.json index 9c7e088b966d33..bd6380bf501c43 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -196,6 +196,8 @@ "@kbn/content-management-table-list-view-common/*": ["packages/content-management/table_list_view_common/*"], "@kbn/content-management-table-list-view-table": ["packages/content-management/table_list_view_table"], "@kbn/content-management-table-list-view-table/*": ["packages/content-management/table_list_view_table/*"], + "@kbn/content-management-user-profiles": ["packages/content-management/user_profiles"], + "@kbn/content-management-user-profiles/*": ["packages/content-management/user_profiles/*"], "@kbn/content-management-utils": ["packages/kbn-content-management-utils"], "@kbn/content-management-utils/*": ["packages/kbn-content-management-utils/*"], "@kbn/controls-example-plugin": ["examples/controls_example"], diff --git a/yarn.lock b/yarn.lock index 07416bc65a2e43..abdb1cfe29213a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3545,6 +3545,10 @@ version "0.0.0" uid "" +"@kbn/content-management-user-profiles@link:packages/content-management/user_profiles": + version "0.0.0" + uid "" + "@kbn/content-management-utils@link:packages/kbn-content-management-utils": version "0.0.0" uid "" From cb11a1b004b062af9757f8d838e6d1669d544739 Mon Sep 17 00:00:00 2001 From: Paulo Henrique Date: Tue, 18 Jun 2024 11:08:01 -0700 Subject: [PATCH 051/123] [Cloud Security] Adding MSW for mocking server responses in React integration tests (#184555) ## Summary It closes #183977 This PR introduces the MSW library into Kibana and setups for MSW usage with Jest for integration testing of React components in the Cloud Security Posture plugin. It also adds the setup for the initial [handlers](https://mswjs.io/docs/concepts/request-handler/), and configures a test for the `` components using MSW to exemplify how the library works. ### Problem Statement Currently, integration tests for React components that interact with the server are hard to write and maintain, as they often require mocking functions implementation and responses, this can lead to tests that do not accurately verify the intended functionality and can be hard to maintain as the implementation of the functions changes. This leads to situations our team faces now, where due to the difficult maintainability of integration tests, we rely much more on End-to-End tests, and maintaining those many End-to-End comes with its own set of tradeoffs, as oftentimes End-to-End tests are detected by the CI as failing or flaky, and as flakiness can happen in End-to-end tests due to its nature of multiple integrated systems, this concept proposes that it's better to reserve End-to-end tests for the features in the most critical path and tests that test multiple integrated systems as those will benefit most of the end-to-end testing. For all the other tests we should focus on unit and integration tests. ### How MSW works MSW is a library that allows you to mock server responses in your tests, it works by intercepting the requests made by the client and returning the mocked responses, this way we can test how the client behaves in different states of the lifecycle such as loading, error, and success. This proposes that we should use MSW to enhance our integration tests, and give preference to writing integration tests over End-to-End tests whenever possible, but this doesn't mean that we should stop writing end-to-end tests, as end-to-end tests are still important for the features in the most critical path and tests that tests multiple integrated systems. ### MSW Diagram Here's a diagram that shows how MSW works with Jest tests: ```mermaid %%{init:{'themeCSS':' g:nth-of-type(3) rect.actor { fill: #eee; };g:nth-of-type(7) rect.actor { fill: #eee; };'}}%% sequenceDiagram participant ReactComponent as React Component participant API as API participant MSW as MSW Mock Server participant Jest as Jest Test Jest->>ReactComponent: Setup component test and mock providers Jest->>MSW: Setup Mock Server Note over Jest,MSW: start listening for requests activate MSW ReactComponent->>API: Make API Call Note over ReactComponent,API: loading state activate API MSW-->>API: Intercepts API Call deactivate API alt is success MSW-->>ReactComponent: Send Mocked success Response else is error MSW-->>ReactComponent: Send Mocked error Response end deactivate MSW ReactComponent-->>Jest: Receive Mocked data and render ``` ### Documentation - Refer to this [PR](https://github.com/elastic/security-team/pull/9624) containing the documentation of how MSW works and how to use it. - Refer to this [presentation](https://docs.google.com/presentation/d/1KYtBaeDMZrpoU5lnKASm8GvCxhrXVqMKxWgR-Xvaxzc/edit#slide=id.g11f0f180654_1_0) to understand the main motivations behind this proposal. ### How to test it ``` yarn test:jest x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx ``` ### Screenshot ![image](https://github.com/elastic/kibana/assets/19270322/f0673be2-f087-42b5-8ed6-42ce3159e378) Intercepted requests logged with `{debug: true}`: ![image](https://github.com/elastic/kibana/assets/19270322/b512d486-8a2a-422e-bf26-3c6b60a8c6d2) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- package.json | 1 + renovate.json | 8 + .../cloud_security_posture/jest.config.js | 9 + .../use_license_management_locator_api.tsx | 20 +- .../components/cloud_posture_page.test.tsx | 17 +- .../public/components/cloud_posture_page.tsx | 10 +- .../components/no_findings_states.test.tsx | 245 ----------------- .../components/no_findings_states/index.ts | 8 + .../no_findings_states.handlers.mock.ts | 20 ++ .../no_findings_states.test.tsx | 163 ++++++++++++ .../no_findings_states.tsx | 46 ++-- .../components/subscription_not_allowed.tsx | 13 +- .../test/fixtures/get_mock_dependencies.ts | 28 ++ .../public/test/mock_server/handlers/index.ts | 15 ++ .../handlers/licensing.handlers.mock.ts | 32 +++ .../public/test/mock_server/mock_server.ts | 174 ++++++++++++ .../mock_server/mock_server_test_provider.tsx | 41 +++ .../public/test/test_provider.tsx | 30 +-- .../benchmarks/benchmarks.handlers.mock.ts | 192 ++++++++++++++ .../routes/status/status.handlers.mock.ts | 251 ++++++++++++++++++ yarn.lock | 205 ++++++++++++-- 21 files changed, 1182 insertions(+), 346 deletions(-) delete mode 100644 x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx create mode 100644 x-pack/plugins/cloud_security_posture/public/components/no_findings_states/index.ts create mode 100644 x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.handlers.mock.ts create mode 100644 x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.test.tsx rename x-pack/plugins/cloud_security_posture/public/components/{ => no_findings_states}/no_findings_states.tsx (90%) create mode 100644 x-pack/plugins/cloud_security_posture/public/test/fixtures/get_mock_dependencies.ts create mode 100644 x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/index.ts create mode 100644 x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/licensing.handlers.mock.ts create mode 100644 x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts create mode 100644 x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server_test_provider.tsx create mode 100644 x-pack/plugins/cloud_security_posture/server/routes/benchmarks/benchmarks.handlers.mock.ts create mode 100644 x-pack/plugins/cloud_security_posture/server/routes/status/status.handlers.mock.ts diff --git a/package.json b/package.json index 989341509eb043..338db19ea67a11 100644 --- a/package.json +++ b/package.json @@ -1675,6 +1675,7 @@ "mochawesome-merge": "^4.3.0", "mock-fs": "^5.1.2", "ms-chromium-edge-driver": "^0.5.1", + "msw": "^2.3.1", "multistream": "^4.1.0", "mutation-observer": "^1.0.3", "native-hdr-histogram": "^1.0.0", diff --git a/renovate.json b/renovate.json index 2cb7a55cfb4aed..f0995502bb1bcc 100644 --- a/renovate.json +++ b/renovate.json @@ -427,6 +427,14 @@ "prCreation": "not-pending", "minimumReleaseAge": "7 days", "enabled": true + }, + { + "groupName": "MSW", + "matchPackageNames": ["msw"], + "reviewers": ["team:kibana-cloud-security-posture"], + "matchBaseBranches": ["main"], + "labels": ["Team: Cloud Security", "release_note:skip", "backport:skip"], + "enabled": true } ] } diff --git a/x-pack/plugins/cloud_security_posture/jest.config.js b/x-pack/plugins/cloud_security_posture/jest.config.js index eb1e880646e56f..82ecbd0c855926 100644 --- a/x-pack/plugins/cloud_security_posture/jest.config.js +++ b/x-pack/plugins/cloud_security_posture/jest.config.js @@ -15,4 +15,13 @@ module.exports = { collectCoverageFrom: [ '/x-pack/plugins/cloud_security_posture/{common,public,server}/**/*.{ts,tsx}', ], + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + transformIgnorePatterns: [ + // ignore all node_modules except the modules below (monaco-editor, monaco-yaml, react-monaco-editor, etc) which requires babel transforms to handle dynamic import() + // since ESM modules are not natively supported in Jest yet (https://github.com/facebook/jest/issues/4842) + '[/\\\\]node_modules(?![\\/\\\\](byte-size|monaco-editor|monaco-yaml|monaco-languageserver-types|monaco-marker-data-provider|monaco-worker-manager|vscode-languageserver-types|react-monaco-editor|d3-interpolate|d3-color|langchain|langsmith|@cfworker|gpt-tokenizer|flat|@langchain|msw|@bundled-es-modules))[/\\\\].+\\.js$', + 'packages/kbn-pm/dist/index.js', + '[/\\\\]node_modules(?![\\/\\\\](langchain|langsmith|@langchain))/dist/[/\\\\].+\\.js$', + '[/\\\\]node_modules(?![\\/\\\\](langchain|langsmith|@langchain))/dist/util/[/\\\\].+\\.js$', + ], }; diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_license_management_locator_api.tsx b/x-pack/plugins/cloud_security_posture/public/common/api/use_license_management_locator_api.tsx index 963d9bfae98349..cbfd64b8e60a8a 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_license_management_locator_api.tsx +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_license_management_locator_api.tsx @@ -5,23 +5,21 @@ * 2.0. */ -import { useQuery } from '@tanstack/react-query'; import { useKibana } from '../hooks/use_kibana'; const LICENSE_MANAGEMENT_LOCATOR = 'LICENSE_MANAGEMENT_LOCATOR'; -const getLicenseManagementLocatorKey = 'license_management_url_key'; - +/** + * Hook to get the license management locator + * @returns a callback to navigate to the license management page + */ export const useLicenseManagementLocatorApi = () => { const { share } = useKibana().services; - return useQuery([getLicenseManagementLocatorKey], () => { - const locator = share.url.locators.get(LICENSE_MANAGEMENT_LOCATOR); - // license management does not exist on serverless - if (!locator) return; + const locator = share.url.locators.get(LICENSE_MANAGEMENT_LOCATOR); + + // license management does not exist on serverless + if (!locator) return; - return locator.getUrl({ - page: 'dashboard', - }); - }); + return () => locator.navigate({ page: 'dashboard' }); }; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page.test.tsx index f2e538194a2fac..05fedd4d8adec5 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page.test.tsx @@ -43,12 +43,7 @@ describe('', () => { }) ); - (useLicenseManagementLocatorApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: true, - }) - ); + (useLicenseManagementLocatorApi as jest.Mock).mockImplementation(undefined); }); const renderCloudPosturePage = ( @@ -85,7 +80,10 @@ describe('', () => { }) ); + (useLicenseManagementLocatorApi as jest.Mock).mockImplementation(() => 'http://license-url'); + renderCloudPosturePage(); + expect(screen.getByTestId('has_locator')).toBeInTheDocument(); }); @@ -97,12 +95,7 @@ describe('', () => { }) ); - (useLicenseManagementLocatorApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: undefined, - }) - ); + (useLicenseManagementLocatorApi as jest.Mock).mockImplementation(undefined); renderCloudPosturePage(); expect(screen.getByTestId('no_locator')).toBeInTheDocument(); diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page.tsx index bfcaf85cfc4572..b2f1d892da9073 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page.tsx @@ -15,7 +15,6 @@ import { SubscriptionNotAllowed } from './subscription_not_allowed'; import { useSubscriptionStatus } from '../common/hooks/use_subscription_status'; import { FullSizeCenteredPage } from './full_size_centered_page'; import { CspLoadingState } from './csp_loading_state'; -import { useLicenseManagementLocatorApi } from '../common/api/use_license_management_locator_api'; export const LOADING_STATE_TEST_SUBJECT = 'cloud_posture_page_loading'; export const ERROR_STATE_TEST_SUBJECT = 'cloud_posture_page_error'; @@ -151,9 +150,9 @@ export const defaultNoDataRenderer = () => ( ); -const subscriptionNotAllowedRenderer = (licenseManagementLocator?: string) => ( +const subscriptionNotAllowedRenderer = () => ( - + ); @@ -173,19 +172,18 @@ export const CloudPosturePage = ({ noDataRenderer = defaultNoDataRenderer, }: CloudPosturePageProps) => { const subscriptionStatus = useSubscriptionStatus(); - const getLicenseManagementLocator = useLicenseManagementLocatorApi(); const render = () => { if (subscriptionStatus.isError) { return defaultErrorRenderer(subscriptionStatus.error); } - if (subscriptionStatus.isLoading || getLicenseManagementLocator.isLoading) { + if (subscriptionStatus.isLoading) { return defaultLoadingRenderer(); } if (!subscriptionStatus.data) { - return subscriptionNotAllowedRenderer(getLicenseManagementLocator.data); + return subscriptionNotAllowedRenderer(); } if (!query) { diff --git a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx deleted file mode 100644 index 840aad9af2e949..00000000000000 --- a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states.test.tsx +++ /dev/null @@ -1,245 +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 { render } from '@testing-library/react'; -import { createReactQueryResponse } from '../test/fixtures/react_query'; -import { TestProvider } from '../test/test_provider'; -import { NoFindingsStates } from './no_findings_states'; -import { useCspSetupStatusApi } from '../common/api/use_setup_status_api'; -import { useCspIntegrationLink } from '../common/navigation/use_csp_integration_link'; -import { useLicenseManagementLocatorApi } from '../common/api/use_license_management_locator_api'; -import { useSubscriptionStatus } from '../common/hooks/use_subscription_status'; - -jest.mock('../common/api/use_setup_status_api', () => ({ - useCspSetupStatusApi: jest.fn(), -})); - -jest.mock('../common/navigation/use_csp_integration_link', () => ({ - useCspIntegrationLink: jest.fn(), -})); - -jest.mock('../common/api/use_license_management_locator_api', () => ({ - useLicenseManagementLocatorApi: jest.fn(), -})); - -jest.mock('../common/hooks/use_subscription_status', () => ({ - useSubscriptionStatus: jest.fn(), -})); - -const customRederer = (postureType: 'cspm' | 'kspm') => { - return render( - - - - ); -}; - -describe('NoFindingsStates', () => { - beforeEach(() => { - jest.clearAllMocks(); - - (useSubscriptionStatus as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: true, - }) - ); - - (useLicenseManagementLocatorApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: true, - }) - ); - - (useCspIntegrationLink as jest.Mock).mockReturnValue('http://cspm-or-kspm-integration-link'); - }); - - it('should show the indexing notification when CSPM is not installed and KSPM is indexing', async () => { - (useCspSetupStatusApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: { - cspm: { - status: 'not-deployed', - }, - kspm: { - status: 'indexing', - }, - indicesDetails: [ - { index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' }, - { index: 'logs-cloud_security_posture.findings-default*', status: 'empty' }, - ], - }, - }) - ); - - const { getByText } = customRederer('kspm'); - expect(getByText(/posture evaluation underway/i)).toBeInTheDocument(); - expect( - getByText( - /waiting for data to be collected and indexed. check back later to see your findings/i - ) - ).toBeInTheDocument(); - }); - - it('should show the indexing notification when KSPM is not installed and CSPM is indexing', async () => { - (useCspSetupStatusApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: { - kspm: { - status: 'not-deployed', - }, - cspm: { - status: 'indexing', - }, - indicesDetails: [ - { index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' }, - { index: 'logs-cloud_security_posture.findings-default*', status: 'empty' }, - ], - }, - }) - ); - - const { getByText } = customRederer('cspm'); - expect(getByText(/posture evaluation underway/i)).toBeInTheDocument(); - expect( - getByText( - /waiting for data to be collected and indexed. Check back later to see your findings/i - ) - ).toBeInTheDocument(); - }); - - it('should show the indexing timout notification when CSPM is status is index-timeout', async () => { - (useCspSetupStatusApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: { - kspm: { - status: 'installed', - }, - cspm: { - status: 'index-timeout', - }, - indicesDetails: [ - { index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' }, - { index: 'logs-cloud_security_posture.findings-default*', status: 'empty' }, - ], - }, - }) - ); - - const { getByText } = customRederer('cspm'); - expect(getByText(/waiting for findings data/i)).toBeInTheDocument(); - const indexTimeOutMessage = getByText(/collecting findings is taking longer than expected/i); - expect(indexTimeOutMessage).toBeInTheDocument(); - }); - - it('should show the indexing timout notification when KSPM is status is index-timeout', async () => { - (useCspSetupStatusApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: { - kspm: { - status: 'index-timeout', - }, - cspm: { - status: 'installed', - }, - indicesDetails: [ - { index: 'logs-cloud_security_posture.findings_latest-default', status: 'empty' }, - { index: 'logs-cloud_security_posture.findings-default*', status: 'empty' }, - ], - }, - }) - ); - - const { getByText } = customRederer('kspm'); - expect(getByText(/waiting for findings data/i)).toBeInTheDocument(); - expect(getByText(/collecting findings is taking longer than expected/i)).toBeInTheDocument(); - }); - - it('should show the unprivileged notification when CSPM is status is index-timeout', async () => { - (useCspSetupStatusApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: { - kspm: { - status: 'installed', - }, - cspm: { - status: 'unprivileged', - }, - indicesDetails: [ - { - index: 'logs-cloud_security_posture.findings_latest-default', - status: 'unprivileged', - }, - { index: 'logs-cloud_security_posture.findings-default*', status: 'unprivileged' }, - ], - }, - }) - ); - - const { getByText } = customRederer('cspm'); - expect(getByText(/privileges required/i)).toBeInTheDocument(); - }); - - it('should show the unprivileged notification when KSPM is status is index-timeout', async () => { - (useCspSetupStatusApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: { - kspm: { - status: 'unprivileged', - }, - cspm: { - status: 'installed', - }, - indicesDetails: [ - { - index: 'logs-cloud_security_posture.findings_latest-default', - status: 'unprivileged', - }, - { index: 'logs-cloud_security_posture.findings-default*', status: 'unprivileged' }, - ], - }, - }) - ); - - const { getByText } = customRederer('kspm'); - expect(getByText(/privileges required/i)).toBeInTheDocument(); - }); - - it('should show the not-installed notification when CSPM and KSPM status is not-installed', async () => { - (useCspSetupStatusApi as jest.Mock).mockImplementation(() => - createReactQueryResponse({ - status: 'success', - data: { - kspm: { - status: 'not-installed', - }, - cspm: { - status: 'not-installed', - }, - indicesDetails: [ - { - index: 'logs-cloud_security_posture.findings_latest-default', - status: 'success', - }, - { index: 'logs-cloud_security_posture.findings-default*', status: 'success' }, - ], - }, - }) - ); - - const { getByText } = customRederer('cspm'); - expect(getByText(/learn more about cloud security posture/i)).toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/index.ts b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/index.ts new file mode 100644 index 00000000000000..e136062ed2ccb5 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/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 './no_findings_states'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.handlers.mock.ts b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.handlers.mock.ts new file mode 100644 index 00000000000000..904083ca86f5cf --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.handlers.mock.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 { http, HttpResponse } from 'msw'; + +export const fleetCspPackageHandler = http.get( + `/api/fleet/epm/packages/cloud_security_posture`, + () => { + return HttpResponse.json({ + item: { + name: 'cloud_security_posture', + version: '1.9.0', + }, + }); + } +); diff --git a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.test.tsx new file mode 100644 index 00000000000000..ad3e482f614f58 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.test.tsx @@ -0,0 +1,163 @@ +/* + * 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, waitFor } from '@testing-library/react'; +import { setupMockServer, startMockServer } from '../../test/mock_server/mock_server'; +import { renderWrapper } from '../../test/mock_server/mock_server_test_provider'; +import { NoFindingsStates } from './no_findings_states'; +import * as statusHandlers from '../../../server/routes/status/status.handlers.mock'; +import * as benchmarksHandlers from '../../../server/routes/benchmarks/benchmarks.handlers.mock'; +import { fleetCspPackageHandler } from './no_findings_states.handlers.mock'; + +const server = setupMockServer(); + +const renderNoFindingsStates = (postureType: 'cspm' | 'kspm' = 'cspm') => { + return renderWrapper(); +}; + +describe('NoFindingsStates', () => { + startMockServer(server); + + beforeEach(() => { + server.use(fleetCspPackageHandler); + }); + + it('shows integrations installation prompt with installation links when integration is not-installed', async () => { + server.use(statusHandlers.notInstalledHandler); + renderNoFindingsStates(); + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + + await waitFor(() => { + expect( + screen.getByText(/detect security misconfigurations in your cloud infrastructure!/i) + ).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getByRole('link', { name: /add cspm integration/i })).toHaveAttribute( + 'href', + '/app/fleet/integrations/cloud_security_posture-1.9.0/add-integration/cspm' + ); + }); + + await waitFor(() => { + expect(screen.getByRole('link', { name: /add kspm integration/i })).toHaveAttribute( + 'href', + '/app/fleet/integrations/cloud_security_posture-1.9.0/add-integration/kspm' + ); + }); + }); + it('shows install agent prompt with install agent link when status is not-deployed', async () => { + server.use(statusHandlers.notDeployedHandler); + server.use(benchmarksHandlers.cspmInstalledHandler); + renderNoFindingsStates(); + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByText(/no agents installed/i)).toBeInTheDocument(); + }); + + await waitFor(() => { + expect(screen.getByRole('link', { name: /install agent/i })).toHaveAttribute( + 'href', + '/app/integrations/detail/cloud_security_posture-1.9.0/policies?addAgentToPolicyId=30cba674-531c-4225-b392-3f7810957511&integration=630f3e42-659e-4499-9007-61e36adf1d97' + ); + }); + }); + it('shows install agent prompt with install agent link when status is not-deployed and postureType is KSPM', async () => { + server.use(statusHandlers.notDeployedHandler); + server.use(benchmarksHandlers.kspmInstalledHandler); + renderNoFindingsStates('kspm'); + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByText(/no agents installed/i)).toBeInTheDocument(); + }); + + await waitFor(() => { + const link = screen.getByRole('link', { + name: /install agent/i, + }); + expect(link).toHaveAttribute( + 'href', + '/app/integrations/detail/cloud_security_posture-1.9.0/policies?addAgentToPolicyId=e2f72eea-bf76-4576-bed8-e29d2df102a7&integration=6aedf856-bc21-49aa-859a-a0952789f898' + ); + }); + }); + it('shows indexing message when status is indexing', async () => { + server.use(statusHandlers.indexingHandler); + + renderNoFindingsStates(); + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByText(/posture evaluation underway/i)).toBeInTheDocument(); + }); + + expect( + screen.getByText( + /waiting for data to be collected and indexed. check back later to see your findings/i + ) + ).toBeInTheDocument(); + }); + it('shows timeout message when status is index-timeout', async () => { + server.use(statusHandlers.indexTimeoutHandler); + + renderNoFindingsStates(); + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + + await waitFor(() => { + screen.getByRole('heading', { + name: /waiting for findings data/i, + }); + }); + + expect( + screen.getByText(/collecting findings is taking longer than expected/i) + ).toBeInTheDocument(); + }); + it('shows unprivileged message when status is unprivileged', async () => { + server.use(statusHandlers.unprivilegedHandler); + + renderNoFindingsStates(); + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText(/privileges required/i)).toBeInTheDocument(); + + expect( + screen.getByText(/required elasticsearch index privilege for the following indices:/i) + ).toBeInTheDocument(); + expect( + screen.getByText('logs-cloud_security_posture.findings_latest-default') + ).toBeInTheDocument(); + expect(screen.getByText('logs-cloud_security_posture.findings-default*')).toBeInTheDocument(); + expect(screen.getByText('logs-cloud_security_posture.scores-default')).toBeInTheDocument(); + expect( + screen.getByText('logs-cloud_security_posture.vulnerabilities_latest-default') + ).toBeInTheDocument(); + }); + }); + it('renders empty container when the status does not match a no finding status', async () => { + server.use(statusHandlers.indexedHandler); + + const { container } = renderNoFindingsStates(); + + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.queryByText(/loading/i)).not.toBeInTheDocument(); + }); + expect(container).toMatchInlineSnapshot(` +
+
+
+ `); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states.tsx b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.tsx similarity index 90% rename from x-pack/plugins/cloud_security_posture/public/components/no_findings_states.tsx rename to x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.tsx index 8e202077199409..97dfce7b84c1ec 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.tsx @@ -20,21 +20,21 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; -import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../common/constants'; -import { FullSizeCenteredPage } from './full_size_centered_page'; -import { useCISIntegrationPoliciesLink } from '../common/navigation/use_navigate_to_cis_integration_policies'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../../common/constants'; +import { FullSizeCenteredPage } from '../full_size_centered_page'; +import { useCISIntegrationPoliciesLink } from '../../common/navigation/use_navigate_to_cis_integration_policies'; import { CSPM_NOT_INSTALLED_ACTION_SUBJ, KSPM_NOT_INSTALLED_ACTION_SUBJ, NO_FINDINGS_STATUS_TEST_SUBJ, -} from './test_subjects'; -import { CloudPosturePage, PACKAGE_NOT_INSTALLED_TEST_SUBJECT } from './cloud_posture_page'; -import { useCspSetupStatusApi } from '../common/api/use_setup_status_api'; -import type { IndexDetails, PostureTypes, CspStatusCode } from '../../common/types_old'; -import noDataIllustration from '../assets/illustrations/no_data_illustration.svg'; -import { useCspIntegrationLink } from '../common/navigation/use_csp_integration_link'; -import { NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS } from '../common/constants'; -import { cspIntegrationDocsNavigation } from '../common/navigation/constants'; +} from '../test_subjects'; +import { CloudPosturePage, PACKAGE_NOT_INSTALLED_TEST_SUBJECT } from '../cloud_posture_page'; +import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; +import type { IndexDetails, PostureTypes, CspStatusCode } from '../../../common/types_old'; +import noDataIllustration from '../../assets/illustrations/no_data_illustration.svg'; +import { useCspIntegrationLink } from '../../common/navigation/use_csp_integration_link'; +import { NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS } from '../../common/constants'; +import { cspIntegrationDocsNavigation } from '../../common/navigation/constants'; const NotDeployed = ({ postureType }: { postureType: PostureTypes }) => { const integrationPoliciesLink = useCISIntegrationPoliciesLink({ @@ -169,13 +169,10 @@ const Unprivileged = ({ unprivilegedIndices }: { unprivilegedIndices: string[] } /> ); -const EmptySecurityFindingsPrompt = ({ - kspmIntegrationLink, - cspmIntegrationLink, -}: { - kspmIntegrationLink?: string; - cspmIntegrationLink?: string; -}) => { +const EmptySecurityFindingsPrompt = () => { + const kspmIntegrationLink = useCspIntegrationLink(KSPM_POLICY_TEMPLATE); + const cspmIntegrationLink = useCspIntegrationLink(CSPM_POLICY_TEMPLATE); + return ( { - const kspmIntegrationLink = useCspIntegrationLink(KSPM_POLICY_TEMPLATE); - const cspmIntegrationLink = useCspIntegrationLink(CSPM_POLICY_TEMPLATE); - const unprivilegedIndices = indicesStatus && indicesStatus @@ -267,13 +263,7 @@ const NoFindingsStatesNotification = ({ return ; if (status === 'indexing' || status === 'waiting_for_results') return ; if (status === 'index-timeout') return ; - if (isNotInstalled) - return ( - - ); + if (isNotInstalled) return ; if (status === 'not-deployed') return ; return null; diff --git a/x-pack/plugins/cloud_security_posture/public/components/subscription_not_allowed.tsx b/x-pack/plugins/cloud_security_posture/public/components/subscription_not_allowed.tsx index a2d8f4fe32c0b8..e527a2f9f0c0c0 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/subscription_not_allowed.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/subscription_not_allowed.tsx @@ -8,12 +8,11 @@ import React from 'react'; import { EuiEmptyPrompt, EuiLink, EuiPageSection } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useLicenseManagementLocatorApi } from '../common/api/use_license_management_locator_api'; + +export const SubscriptionNotAllowed = () => { + const handleNavigateToLicenseManagement = useLicenseManagementLocatorApi(); -export const SubscriptionNotAllowed = ({ - licenseManagementLocator, -}: { - licenseManagementLocator?: string; -}) => { return ( } body={ - licenseManagementLocator ? ( + handleNavigateToLicenseManagement ? (

+ ({ + data: dataPluginMock.createStartContract(), + unifiedSearch: unifiedSearchPluginMock.createStartContract(), + charts: chartPluginMock.createStartContract(), + discover: discoverPluginMock.createStartContract(), + fleet: fleetMock.createStartMock(), + licensing: licensingMock.createStart(), + uiActions: uiActionsPluginMock.createStartContract(), + storage: sessionStorageMock.create(), + share: sharePluginMock.createStartContract(), +}); diff --git a/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/index.ts b/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/index.ts new file mode 100644 index 00000000000000..91eb25630b2225 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/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 { defaultApiLicensingInfo } from './licensing.handlers.mock'; + +/** + * Default handlers for the mock server, these are the handlers that are always enabled + * when the mock server is started, but can be overridden by specific tests when needed. + * Recommended to use these handlers for common endpoints. + */ +export const defaultHandlers = [defaultApiLicensingInfo]; diff --git a/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/licensing.handlers.mock.ts b/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/licensing.handlers.mock.ts new file mode 100644 index 00000000000000..de426f5c72144e --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/licensing.handlers.mock.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { http, HttpResponse } from 'msw'; + +export const MOCK_SERVER_LICENSING_INFO_URL = `/api/licensing/info`; + +export const defaultApiLicensingInfo = http.get(MOCK_SERVER_LICENSING_INFO_URL, () => { + const date = new Date(); + const expiryDateInMillis = date.setDate(date.getDate() + 30); + + return HttpResponse.json({ + license: { + uid: '000000-0000-0000-0000-000000000', + type: 'trial', + mode: 'trial', + expiryDateInMillis, + status: 'active', + }, + features: { + security: { + isAvailable: true, + isEnabled: true, + }, + }, + signature: '0000000000000000000000000000000000000000000000000000000', + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts new file mode 100644 index 00000000000000..9fe4b156bc0962 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts @@ -0,0 +1,174 @@ +/* + * 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 { setupServer, SetupServerApi } from 'msw/node'; +import { coreMock } from '@kbn/core/public/mocks'; +import type { CoreStart } from '@kbn/core/public'; +import { licenseMock } from '@kbn/licensing-plugin/common/licensing.mock'; +import { createStubDataView } from '@kbn/data-views-plugin/common/stubs'; +import { indexPatternFieldEditorPluginMock as dataViewFieldEditorMock } from '@kbn/data-view-field-editor-plugin/public/mocks'; +import SearchBar from '@kbn/unified-search-plugin/public/search_bar/search_bar'; +import { http, HttpResponse, JsonBodyType } from 'msw'; +import { defaultHandlers } from './handlers'; +import { getMockDependencies } from '../fixtures/get_mock_dependencies'; +import { CspClientPluginStartDeps } from '../../types'; +import { MOCK_SERVER_LICENSING_INFO_URL } from './handlers/licensing.handlers.mock'; + +/** + * Mock the lastValueFrom function from rxjs to return the result of the promise instead of the Observable + * This is for simplifying the testing by avoiding the need to subscribe to the Observable while producing the same result + */ +jest.mock('rxjs', () => { + const actual = jest.requireActual('rxjs'); + return { + ...actual, + lastValueFrom: async (source: Promise) => { + const value = await source; + return value.result; + }, + }; +}); + +/** + * Setup a mock server with the default handlers + * @param debug - If true, log all requests to the console + * @returns The mock server + */ +export const setupMockServer = ({ debug = false }: { debug?: boolean } = {}) => { + const server = setupServer(...defaultHandlers); + + if (debug) { + // Debug: log all requests to the console + server.events.on('request:start', async ({ request }) => { + const payload = await request.clone().text(); + // eslint-disable-next-line no-console + console.log('MSW intercepted request:', request.method, request.url, payload); + }); + server.events.on('response:mocked', async ({ request, response }) => { + const body = await response.json(); + // eslint-disable-next-line no-console + console.log( + '%s %s received %s %s %s', + request.method, + request.url, + response.status, + response.statusText, + JSON.stringify(body, null, 2) + ); + }); + } + return server; +}; + +/** + * This function wraps beforeAll, afterAll and beforeEach for setup MSW server into a single call. + * That makes the describe code further down easier to read and makes + * sure we don't forget the handlers. Can easily be shared between tests. + * @param server - The MSW server instance, created with setupMockServer + */ +export const startMockServer = (server: SetupServerApi) => { + beforeAll(() => server.listen({ onUnhandledRequest: 'warn' })); + afterAll(() => server.close()); + beforeEach(() => { + server.resetHandlers(); + }); +}; + +const MOCK_SERVER_BASE_URL = 'http://localhost'; + +/** + * Get a set of dependencies for the mock server overriding default mock dependencies to perform + * HTTP calls that will be intercepted by the mock server + * @returns The core and deps dependencies used by the KibanaContextProvider + */ +export const getMockServerDependencies = () => { + return { + deps: { + ...getMockDependencies(), + data: { + ...getMockDependencies().data, + search: { + ...getMockDependencies().data.search, + search: async ({ params }: { params: any }) => { + const response = await fetch(`${MOCK_SERVER_BASE_URL}/internal/bsearch`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(params), + }); + return response.json(); + }, + }, + dataViews: { + ...getMockDependencies().data.dataViews, + find: async (pattern: string) => { + const response = await fetch( + `${MOCK_SERVER_BASE_URL}/internal/data_views/fields?pattern=${pattern}` + ); + + const responseJson = await response.json(); + + const fields = responseJson.fields.reduce((acc: any, field: any) => { + acc[field.name] = field; + return acc; + }, {}); + + const dataView = createStubDataView({ + spec: { + id: pattern, + title: pattern, + fields, + }, + }); + + return [dataView]; + }, + }, + }, + licensing: { + ...getMockDependencies().licensing, + refresh: async () => { + const response = await fetch(MOCK_SERVER_LICENSING_INFO_URL); + const responseJson = await response.json(); + return licenseMock.createLicense(responseJson); + }, + }, + dataViewFieldEditor: dataViewFieldEditorMock.createStartContract(), + unifiedSearch: { + ...getMockDependencies().unifiedSearch, + ui: { + ...getMockDependencies().unifiedSearch.ui, + SearchBar, + }, + }, + storage: { + ...getMockDependencies().storage, + get: (key: string) => { + return localStorage.getItem(key); + }, + set: (key: string, value: string) => { + localStorage.setItem(key, value); + }, + }, + } as unknown as Partial, + core: { + ...coreMock.createStart(), + http: { + ...coreMock.createStart().http, + get: async (path: string, options: any) => { + const response = await fetch(`${MOCK_SERVER_BASE_URL}${path}`, options); + return response.json(); + }, + }, + } as unknown as CoreStart, + }; +}; + +export const mockGetRequest = (path: string, response: JsonBodyType) => { + return http.get(path, () => HttpResponse.json(response)); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server_test_provider.tsx b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server_test_provider.tsx new file mode 100644 index 00000000000000..19143d46418363 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server_test_provider.tsx @@ -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 React from 'react'; +import { render } from '@testing-library/react'; +import type { CoreStart } from '@kbn/core/public'; +import { CspClientPluginStartDeps } from '../../types'; +import { TestProvider } from '../test_provider'; +import { getMockServerDependencies } from './mock_server'; +interface MockServerDependencies { + deps: Partial; + core: CoreStart; +} + +interface MockServerTestProviderProps { + children: React.ReactNode; + dependencies?: MockServerDependencies; +} + +/** + * Simple wrapper around the TestProvider that provides dependencies for the mock server. + */ +export const MockServerTestProvider = ({ + children, + dependencies = getMockServerDependencies(), +}: MockServerTestProviderProps) => { + return {children}; +}; + +/** + * Renders a component wrapped in the MockServerTestProvider. + */ +export const renderWrapper = (children: React.ReactNode, dependencies?: MockServerDependencies) => { + return render( + {children} + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx b/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx index d677df4258837a..ab3173ec8c5819 100755 --- a/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx +++ b/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx @@ -6,23 +6,16 @@ */ import type { AppMountParameters, CoreStart } from '@kbn/core/public'; -import React, { useMemo } from 'react'; +import React from 'react'; import { I18nProvider } from '@kbn/i18n-react'; // eslint-disable-next-line no-restricted-imports import { Router } from 'react-router-dom'; import { Route, Routes } from '@kbn/shared-ux-router'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { coreMock } from '@kbn/core/public/mocks'; -import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; -import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks'; -import { discoverPluginMock } from '@kbn/discover-plugin/public/mocks'; -import { fleetMock } from '@kbn/fleet-plugin/public/mocks'; -import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; -import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; -import { sessionStorageMock } from '@kbn/core-http-server-mocks'; import type { CspClientPluginStartDeps } from '../types'; +import { getMockDependencies } from './fixtures/get_mock_dependencies'; interface CspAppDeps { core: CoreStart; @@ -33,20 +26,17 @@ interface CspAppDeps { export const TestProvider: React.FC> = ({ core = coreMock.createStart(), - deps = { - data: dataPluginMock.createStartContract(), - unifiedSearch: unifiedSearchPluginMock.createStartContract(), - charts: chartPluginMock.createStartContract(), - discover: discoverPluginMock.createStartContract(), - fleet: fleetMock.createStartMock(), - licensing: licensingMock.createStart(), - uiActions: uiActionsPluginMock.createStartContract(), - storage: sessionStorageMock.create(), - }, + deps = getMockDependencies(), params = coreMock.createAppMountParameters(), children, } = {}) => { - const queryClient = useMemo(() => new QueryClient(), []); + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, + }); return ( diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/benchmarks.handlers.mock.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/benchmarks.handlers.mock.ts new file mode 100644 index 00000000000000..ab9d84fbc5b09f --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/benchmarks.handlers.mock.ts @@ -0,0 +1,192 @@ +/* + * 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 { http, HttpResponse } from 'msw'; + +export const cspmInstalledHandler = http.get('/internal/cloud_security_posture/benchmarks', () => { + return HttpResponse.json({ + items: [ + { + package_policy: { + id: '630f3e42-659e-4499-9007-61e36adf1d97', + name: 'cspm-1', + namespace: 'default', + description: '', + package: { + name: 'cloud_security_posture', + title: 'Security Posture Management', + version: '1.9.0', + }, + enabled: true, + policy_id: '30cba674-531c-4225-b392-3f7810957511', + inputs: [ + { + type: 'cloudbeat/cis_aws', + policy_template: 'cspm', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { + type: 'logs', + dataset: 'cloud_security_posture.findings', + }, + vars: { + access_key_id: { + type: 'text', + }, + secret_access_key: { + type: 'text', + }, + session_token: { + type: 'text', + }, + shared_credential_file: { + type: 'text', + }, + credential_profile_name: { + type: 'text', + }, + role_arn: { + type: 'text', + }, + 'aws.credentials.type': { + type: 'text', + }, + 'aws.account_type': { + value: 'organization-account', + type: 'text', + }, + }, + id: 'cloudbeat/cis_aws-cloud_security_posture.findings-630f3e42-659e-4499-9007-61e36adf1d97', + compiled_stream: { + period: '24h', + config: { + v1: { + type: 'cspm', + deployment: 'aws', + benchmark: 'cis_aws', + aws: { + account_type: 'organization-account', + credentials: { + type: null, + }, + }, + }, + }, + }, + }, + ], + config: { + cloud_formation_template_url: { + value: + 'https://console.aws.amazon.com/cloudformation/home#/stacks/quickcreate?templateURL=https://elastic-cspm-cft.s3.eu-central-1.amazonaws.com/cloudformation-cspm-ACCOUNT_TYPE-8.14.0.yml&stackName=Elastic-Cloud-Security-Posture-Management¶m_EnrollmentToken=FLEET_ENROLLMENT_TOKEN¶m_FleetUrl=FLEET_URL¶m_ElasticAgentVersion=KIBANA_VERSION¶m_ElasticArtifactServer=https://artifacts.elastic.co/downloads/beats/elastic-agent', + }, + }, + }, + ], + vars: { + posture: { + value: 'cspm', + type: 'text', + }, + deployment: { + value: 'aws', + type: 'text', + }, + }, + revision: 1, + created_at: '2024-06-03T21:06:20.786Z', + created_by: 'system', + updated_at: '2024-06-03T21:06:20.786Z', + updated_by: 'system', + }, + agent_policy: { + id: '30cba674-531c-4225-b392-3f7810957511', + name: 'Agent policy 3', + agents: 0, + }, + rules_count: 55, + }, + ], + total: 1, + page: 1, + perPage: 100, + }); +}); + +export const kspmInstalledHandler = http.get('/internal/cloud_security_posture/benchmarks', () => { + return HttpResponse.json({ + items: [ + { + package_policy: { + id: '6aedf856-bc21-49aa-859a-a0952789f898', + version: 'WzE4ODcxLDE0XQ==', + name: 'kspm-1', + namespace: 'default', + description: '', + package: { + name: 'cloud_security_posture', + title: 'Security Posture Management', + version: '1.9.0', + }, + enabled: true, + policy_id: 'e2f72eea-bf76-4576-bed8-e29d2df102a7', + inputs: [ + { + type: 'cloudbeat/cis_k8s', + policy_template: 'kspm', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { + type: 'logs', + dataset: 'cloud_security_posture.findings', + }, + id: 'cloudbeat/cis_k8s-cloud_security_posture.findings-6aedf856-bc21-49aa-859a-a0952789f898', + compiled_stream: { + config: { + v1: { + type: 'kspm', + deployment: 'self_managed', + benchmark: 'cis_k8s', + }, + }, + }, + }, + ], + }, + ], + vars: { + posture: { + value: 'kspm', + type: 'text', + }, + deployment: { + value: 'self_managed', + type: 'text', + }, + }, + revision: 1, + created_at: '2024-06-03T21:23:23.139Z', + created_by: 'system', + updated_at: '2024-06-03T21:23:23.139Z', + updated_by: 'system', + }, + agent_policy: { + id: 'e2f72eea-bf76-4576-bed8-e29d2df102a7', + name: 'Agent policy 1', + agents: 0, + }, + rules_count: 92, + }, + ], + total: 1, + page: 1, + perPage: 100, + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/server/routes/status/status.handlers.mock.ts b/x-pack/plugins/cloud_security_posture/server/routes/status/status.handlers.mock.ts new file mode 100644 index 00000000000000..0f2b3b9eab6404 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/status/status.handlers.mock.ts @@ -0,0 +1,251 @@ +/* + * 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 { http, HttpResponse } from 'msw'; + +const STATUS_URL = `/internal/cloud_security_posture/status`; + +export const notInstalledHandler = http.get(STATUS_URL, () => { + return HttpResponse.json({ + cspm: { + status: 'not-installed', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + kspm: { + status: 'not-installed', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + vuln_mgmt: { + status: 'not-installed', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + indicesDetails: [ + { + index: 'logs-cloud_security_posture.findings_latest-default', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.findings-default*', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.scores-default', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.vulnerabilities_latest-default', + status: 'empty', + }, + ], + isPluginInitialized: true, + latestPackageVersion: '1.9.0', + }); +}); + +export const notDeployedHandler = http.get(STATUS_URL, () => { + return HttpResponse.json({ + cspm: { + status: 'not-deployed', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + kspm: { + status: 'not-deployed', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + vuln_mgmt: { + status: 'not-deployed', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + indicesDetails: [ + { + index: 'logs-cloud_security_posture.findings_latest-default', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.findings-default*', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.scores-default', + status: 'not-empty', + }, + { + index: 'logs-cloud_security_posture.vulnerabilities_latest-default', + status: 'empty', + }, + ], + isPluginInitialized: true, + latestPackageVersion: '1.9.0', + installedPackageVersion: '1.9.0', + }); +}); + +export const indexingHandler = http.get(STATUS_URL, () => { + return HttpResponse.json({ + cspm: { + status: 'indexing', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + kspm: { + status: 'indexing', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + vuln_mgmt: { + status: 'indexing', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + indicesDetails: [ + { + index: 'logs-cloud_security_posture.findings_latest-default', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.findings-default*', + status: 'not-empty', + }, + { + index: 'logs-cloud_security_posture.scores-default', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.vulnerabilities_latest-default', + status: 'empty', + }, + ], + isPluginInitialized: true, + latestPackageVersion: '1.9.0', + }); +}); + +export const indexTimeoutHandler = http.get(STATUS_URL, () => { + return HttpResponse.json({ + cspm: { + status: 'index-timeout', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + kspm: { + status: 'index-timeout', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + vuln_mgmt: { + status: 'index-timeout', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + indicesDetails: [ + { + index: 'logs-cloud_security_posture.findings_latest-default', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.findings-default*', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.scores-default', + status: 'empty', + }, + { + index: 'logs-cloud_security_posture.vulnerabilities_latest-default', + status: 'empty', + }, + ], + isPluginInitialized: true, + latestPackageVersion: '1.9.0', + }); +}); + +export const unprivilegedHandler = http.get(STATUS_URL, () => { + return HttpResponse.json({ + cspm: { + status: 'unprivileged', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + kspm: { + status: 'unprivileged', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + vuln_mgmt: { + status: 'unprivileged', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + indicesDetails: [ + { + index: 'logs-cloud_security_posture.findings_latest-default', + status: 'unprivileged', + }, + { + index: 'logs-cloud_security_posture.findings-default*', + status: 'unprivileged', + }, + { + index: 'logs-cloud_security_posture.scores-default', + status: 'unprivileged', + }, + { + index: 'logs-cloud_security_posture.vulnerabilities_latest-default', + status: 'unprivileged', + }, + ], + isPluginInitialized: true, + latestPackageVersion: '1.9.0', + }); +}); + +export const indexedHandler = http.get(STATUS_URL, () => { + return HttpResponse.json({ + cspm: { + status: 'indexed', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + kspm: { + status: 'indexed', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + vuln_mgmt: { + status: 'indexed', + healthyAgents: 1, + installedPackagePolicies: 1, + }, + indicesDetails: [ + { + index: 'logs-cloud_security_posture.findings_latest-default', + status: 'not-empty', + }, + { + index: 'logs-cloud_security_posture.findings-default*', + status: 'not-empty', + }, + { + index: 'logs-cloud_security_posture.scores-default', + status: 'not-empty', + }, + { + index: 'logs-cloud_security_posture.vulnerabilities_latest-default', + status: 'not-empty', + }, + ], + isPluginInitialized: true, + latestPackageVersion: '1.9.0', + installedPackageVersion: '1.9.0', + }); +}); diff --git a/yarn.lock b/yarn.lock index abdb1cfe29213a..a5738570ec3874 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1431,6 +1431,20 @@ resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.2.1.tgz#f8b1fbbe79726a4eafa9772ddde147b57f85d177" integrity sha512-cwwGvLGqvoaOZmoP5+i4v/rbW+rHkguvTehuZyM2p/xpmaNSdT2h3B7kHw33aiffv35t1XrYHIkdJSEkSEMJuA== +"@bundled-es-modules/cookie@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz#c3b82703969a61cf6a46e959a012b2c257f6b164" + integrity sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw== + dependencies: + cookie "^0.5.0" + +"@bundled-es-modules/statuses@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz#761d10f44e51a94902c4da48675b71a76cc98872" + integrity sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg== + dependencies: + statuses "^2.0.1" + "@cbor-extract/cbor-extract-darwin-arm64@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.0.0.tgz#cf0667e4c22111c9d45e16c29964892b12460a76" @@ -2830,6 +2844,43 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@inquirer/confirm@^3.0.0": + version "3.1.8" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.1.8.tgz#db80f23f775d9b980c6de2425dde39f9786bf1d3" + integrity sha512-f3INZ+ca4dQdn+MQiq1yP/mOIR/Oc8BLRYuDh6ciToWd6z4W8yArfzjBCMQ0BPY8PcJKwZxGIt8Z6yNT32eSTw== + dependencies: + "@inquirer/core" "^8.2.1" + "@inquirer/type" "^1.3.2" + +"@inquirer/core@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-8.2.1.tgz#ee92c2bf25f378819f56290f8ed8bfef8c6cc94d" + integrity sha512-TIcuQMn2qrtyYe0j136UpHeYpk7AcR/trKeT/7YY0vRgcS9YSfJuQ2+PudPhSofLLsHNnRYAHScQCcVZrJkMqA== + dependencies: + "@inquirer/figures" "^1.0.2" + "@inquirer/type" "^1.3.2" + "@types/mute-stream" "^0.0.4" + "@types/node" "^20.12.12" + "@types/wrap-ansi" "^3.0.0" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + cli-spinners "^2.9.2" + cli-width "^4.1.0" + mute-stream "^1.0.0" + signal-exit "^4.1.0" + strip-ansi "^6.0.1" + wrap-ansi "^6.2.0" + +"@inquirer/figures@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.2.tgz#a6af5e9f9969efb9ed3469130566315c36506b8a" + integrity sha512-4F1MBwVr3c/m4bAUef6LgkvBfSjzwH+OfldgHqcuacWwSUetFebM2wi58WfG9uk1rR98U6GwLed4asLJbwdV5w== + +"@inquirer/type@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.3.2.tgz#439b0b50c152c89fd369d2a17eff54869b4d79b8" + integrity sha512-5Frickan9c89QbPkSu6I6y8p+9eR6hZkdPahGmNDsTFX8FHLPAozyzCZMKUeW8FyYwnlCKUjqIEqxY+UctARiw== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -7305,6 +7356,23 @@ resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407" integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ== +"@mswjs/cookies@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-1.1.0.tgz#1528eb43630caf83a1d75d5332b30e75e9bb1b5b" + integrity sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw== + +"@mswjs/interceptors@^0.29.0": + version "0.29.1" + resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.29.1.tgz#e77fc58b5188569041d0440b25c9e9ebb1ccd60a" + integrity sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw== + dependencies: + "@open-draft/deferred-promise" "^2.2.0" + "@open-draft/logger" "^0.3.0" + "@open-draft/until" "^2.0.0" + is-node-process "^1.2.0" + outvariant "^1.2.1" + strict-event-emitter "^0.5.1" + "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" @@ -7603,6 +7671,24 @@ dependencies: "@octokit/openapi-types" "^18.0.0" +"@open-draft/deferred-promise@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz#4a822d10f6f0e316be4d67b4d4f8c9a124b073bd" + integrity sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA== + +"@open-draft/logger@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@open-draft/logger/-/logger-0.3.0.tgz#2b3ab1242b360aa0adb28b85f5d7da1c133a0954" + integrity sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ== + dependencies: + is-node-process "^1.2.0" + outvariant "^1.4.0" + +"@open-draft/until@^2.0.0", "@open-draft/until@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" + integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== + "@opentelemetry/api-metrics@0.31.0", "@opentelemetry/api-metrics@^0.31.0": version "0.31.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api-metrics/-/api-metrics-0.31.0.tgz#0ed4cf4d7c731f968721c2b303eaf5e9fd42f736" @@ -9783,6 +9869,11 @@ dependencies: "@types/node" "*" +"@types/cookie@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5" + integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA== + "@types/cookiejar@^2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78" @@ -10474,6 +10565,13 @@ resolved "https://registry.yarnpkg.com/@types/mustache/-/mustache-0.8.31.tgz#7c86cbf74f7733f9e3bdc28817623927eb386616" integrity sha512-72flCZJkEJHPwhmpHgg4a0ZBLssMhg5NB0yltRblRlZMo4py3B/u/d7icevc4EeN9MPQUo/dPtuVOoVy9ih6cQ== +"@types/mute-stream@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" + integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow== + dependencies: + "@types/node" "*" + "@types/nock@^10.0.3": version "10.0.3" resolved "https://registry.yarnpkg.com/@types/nock/-/nock-10.0.3.tgz#dab1d18ffbccfbf2db811dab9584304eeb6e1c4c" @@ -10511,7 +10609,7 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@14 || 16 || 17", "@types/node@20.10.5", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=18.0.0", "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0", "@types/node@^18.0.0", "@types/node@^18.11.18": +"@types/node@*", "@types/node@14 || 16 || 17", "@types/node@20.10.5", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=18.0.0", "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0", "@types/node@^18.0.0", "@types/node@^18.11.18", "@types/node@^20.12.12": version "20.10.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2" integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw== @@ -10929,6 +11027,11 @@ resolved "https://registry.yarnpkg.com/@types/stats-lite/-/stats-lite-2.2.0.tgz#bc8190bf9dfa1e16b89eaa2b433c99dff0804de9" integrity sha512-YV6SS4QC+pbzqjMIV8qVSTDOOazgKBLTVaN+7PfuxELjz/eyzc20KwDVGPrbHt2OcYMA7K2ezLB45Cp6DpNOSQ== +"@types/statuses@^2.0.4": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/statuses/-/statuses-2.0.5.tgz#f61ab46d5352fd73c863a1ea4e1cef3b0b51ae63" + integrity sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A== + "@types/styled-components@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.0.tgz#24d3412ba5395aa06e14fbc93c52f9454cebd0d6" @@ -11139,6 +11242,11 @@ tapable "^2.2.0" webpack "^5" +"@types/wrap-ansi@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" + integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== + "@types/ws@*", "@types/ws@^8.5.1": version "8.5.3" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" @@ -11892,12 +12000,12 @@ ansi-colors@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== -ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d" - integrity sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg== +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: - type-fest "^0.8.1" + type-fest "^0.21.3" ansi-escapes@^6.2.0: version "6.2.1" @@ -13922,7 +14030,7 @@ cli-progress@^3.12.0: dependencies: string-width "^4.2.3" -cli-spinners@^2.2.0, cli-spinners@^2.5.0: +cli-spinners@^2.2.0, cli-spinners@^2.5.0, cli-spinners@^2.9.2: version "2.9.2" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== @@ -13957,6 +14065,11 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + client-only@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" @@ -18725,7 +18838,7 @@ graphql-tag@^2.12.6: dependencies: tslib "^2.1.0" -graphql@^16.6.0: +graphql@^16.6.0, graphql@^16.8.1: version "16.8.1" resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== @@ -19081,6 +19194,11 @@ he@1.2.0, he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +headers-polyfill@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.3.tgz#922a0155de30ecc1f785bcf04be77844ca95ad07" + integrity sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ== + heap@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" @@ -20083,6 +20201,11 @@ is-nil@^1.0.0: resolved "https://registry.yarnpkg.com/is-nil/-/is-nil-1.0.1.tgz#2daba29e0b585063875e7b539d071f5b15937969" integrity sha1-LauingtYUGOHXntTnQcfWxWTeWk= +is-node-process@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" + integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw== + is-npm@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-6.0.0.tgz#b59e75e8915543ca5d881ecff864077cba095261" @@ -23336,6 +23459,29 @@ msgpackr@^1.9.9: optionalDependencies: msgpackr-extract "^3.0.2" +msw@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/msw/-/msw-2.3.1.tgz#bfc73e256ffc2c74ec4381b604abb258df35f32b" + integrity sha512-ocgvBCLn/5l3jpl1lssIb3cniuACJLoOfZu01e3n5dbJrpA5PeeWn28jCLgQDNt6d7QT8tF2fYRzm9JoEHtiig== + dependencies: + "@bundled-es-modules/cookie" "^2.0.0" + "@bundled-es-modules/statuses" "^1.0.1" + "@inquirer/confirm" "^3.0.0" + "@mswjs/cookies" "^1.1.0" + "@mswjs/interceptors" "^0.29.0" + "@open-draft/until" "^2.1.0" + "@types/cookie" "^0.6.0" + "@types/statuses" "^2.0.4" + chalk "^4.1.2" + graphql "^16.8.1" + headers-polyfill "^4.0.2" + is-node-process "^1.2.0" + outvariant "^1.4.2" + path-to-regexp "^6.2.0" + strict-event-emitter "^0.5.1" + type-fest "^4.9.0" + yargs "^17.7.2" + multicast-dns@^7.2.5: version "7.2.5" resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" @@ -23385,6 +23531,11 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mute-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" + integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== + nan@^2.18.0: version "2.18.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" @@ -24342,6 +24493,11 @@ ospath@^1.2.2: resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" integrity sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs= +outvariant@^1.2.1, outvariant@^1.4.0, outvariant@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.2.tgz#f54f19240eeb7f15b28263d5147405752d8e2066" + integrity sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ== + p-all@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-all/-/p-all-2.1.0.tgz#91419be56b7dee8fe4c5db875d55e0da084244a0" @@ -24737,6 +24893,11 @@ path-to-regexp@^2.2.1: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.4.0.tgz#35ce7f333d5616f1c1e1bfe266c3aba2e5b2e704" integrity sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w== +path-to-regexp@^6.2.0: + version "6.2.2" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.2.tgz#324377a83e5049cbecadc5554d6a63a9a4866b36" + integrity sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw== + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -28261,10 +28422,10 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967" - integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q== +signal-exit@^4.0.1, signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== simple-bin-help@^1.8.0: version "1.8.0" @@ -28938,7 +29099,7 @@ stats-lite@^2.2.0: dependencies: isnumber "~1.0.0" -statuses@2.0.1: +statuses@2.0.1, statuses@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== @@ -29026,6 +29187,11 @@ streamx@^2.12.0, streamx@^2.12.5, streamx@^2.13.0, streamx@^2.13.2, streamx@^2.1 optionalDependencies: bare-events "^2.2.0" +strict-event-emitter@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93" + integrity sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ== + strict-uri-encode@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" @@ -30286,6 +30452,11 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" @@ -30306,10 +30477,10 @@ type-fest@^2.13.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -type-fest@^4.15.0, type-fest@^4.17.0: - version "4.17.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.17.0.tgz#4c1b2c2852d2a40ba8c0236d3afc6fc68229e5bf" - integrity sha512-9flrz1zkfLRH3jO3bLflmTxryzKMxVa7841VeMgBaNQGY6vH4RCcpN/sQLB7mQQYh1GZ5utT2deypMuCy4yicw== +type-fest@^4.15.0, type-fest@^4.17.0, type-fest@^4.9.0: + version "4.18.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.18.3.tgz#5249f96e7c2c3f0f1561625f54050e343f1c8f68" + integrity sha512-Q08/0IrpvM+NMY9PA2rti9Jb+JejTddwmwmVQGskAlhtcrw1wsRzoR6ode6mR+OAabNa75w/dxedSUY2mlphaQ== type-is@~1.6.18: version "1.6.18" From 962368ce2fcd190857694496e6ef2d042c4b5424 Mon Sep 17 00:00:00 2001 From: Elastic Machine Date: Wed, 19 Jun 2024 04:41:16 +1000 Subject: [PATCH 052/123] [main] Sync bundled packages with Package Storage (#186399) Automated by https://buildkite.com/elastic/package-storage-infra-kibana-discover-release-branches/builds/846 --- fleet_packages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fleet_packages.json b/fleet_packages.json index da78baac4651ad..76dd27e8c27f0d 100644 --- a/fleet_packages.json +++ b/fleet_packages.json @@ -30,7 +30,7 @@ }, { "name": "elastic_agent", - "version": "1.19.2" + "version": "1.20.0" }, { "name": "endpoint", From 5a88e4cc37c2b17999cf70aca99a17ac3391cf7a Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 18 Jun 2024 20:50:21 +0200 Subject: [PATCH 053/123] [Security Solution] Support local OpenAPI circular references by code generation (#186221) **Addresses:** https://github.com/elastic/kibana/issues/186066 ## Summary This PR adds `kbn-openapi-generator` support for local OpenAPI circular references. ## Details Circular references represent a problem for OpenAPI adoption since lack of support forces engineers to disable code generation and manually define Zod schemas and related TS types. This PR brings `kbn-openapi-generator` support for local OpenAPI circular references. Local references means references to schemas inside one document which looks like `#/components/schemas/MySchema`. It should cover the majority of cases when circular references support id required. The feature is implemented by detecting local circular references and applying a different generation template for involved in cycles inspired by [Zod recursive types docs section](https://github.com/colinhacks/zod?tab=readme-ov-file#recursive-types) for schemas. It involves TS types generation since TS isn't able to properly infer types in this case and hinting circular Zod schemas via `z.ZodType<>`. On top of that circular schema usages are wrapped in `z.lazy()`. ## What's not implemented? - Multi-file circular references aren't supported ## How to test Security Solution doesn't have OpenAPI circular schemas yet. But generator's behavior has been verified on the following specs - Self-recursive Spec: ```yaml components: x-codegen-enabled: true schemas: SelfRecursive: type: object properties: fieldA: $ref: '#/components/schemas/SelfRecursive' ``` Generated output: ```ts import type { ZodTypeDef } from 'zod'; import { z } from 'zod'; export interface SchemaA { fieldA?: SchemaA; } export interface SchemaAInput { fieldA?: SchemaAInput; } export const SchemaA: z.ZodType = z.object({ fieldA: z.lazy(() => SchemaA).optional(), }); ``` - Two circular schemas Spec: ```yaml components: x-codegen-enabled: true schemas: SchemaA: type: object properties: recursiveFieldB: $ref: '#/components/schemas/SchemaB' SchemaB: type: object properties: recursiveFieldA: $ref: '#/components/schemas/SchemaA' ``` Generated output: ```ts import type { ZodTypeDef } from 'zod'; import { z } from 'zod'; export interface SchemaA { recursiveFieldB?: SchemaB; } export interface SchemaAInput { recursiveFieldB?: SchemaBInput; } export const SchemaA: z.ZodType = z.object({ recursiveFieldB: z.lazy(() => SchemaB).optional(), }); export interface SchemaB { recursiveFieldA?: SchemaA; } export interface SchemaBInput { recursiveFieldA?: SchemaAInput; } export const SchemaB: z.ZodType = z.object({ recursiveFieldA: z.lazy(() => SchemaA).optional(), }); ``` - More complex example with circular with `anyOf` and non circular schemas Spec: ```yaml components: x-codegen-enabled: true schemas: SchemaA: anyOf: - $ref: '#/components/schemas/SchemaB' - $ref: '#/components/schemas/SchemaC' - type: string enum: [valueA, valueB] SchemaB: type: object properties: fieldB: $ref: '#/components/schemas/SchemaC' defaultableField: type: number default: 1 required: [fieldB] SchemaC: type: object properties: fieldC: $ref: '#/components/schemas/SchemaA' SchemaZ: anyOf: - type: object properties: fieldZ: type: string defField: type: number default: 1 required: [fieldZ] - type: object properties: fieldX: type: boolean required: [fieldX] ``` Generated output: ```ts import type { ZodTypeDef } from 'zod'; import { z } from 'zod'; export type SchemaA = SchemaB | SchemaC | 'valueA' | 'valueB'; export type SchemaAInput = SchemaBInput | SchemaCInput | 'valueA' | 'valueB'; export const SchemaA: z.ZodType = z.union([ z.lazy(() => SchemaB), z.lazy(() => SchemaC), z.enum(['valueA', 'valueB']), ]); export interface SchemaB { fieldB: SchemaC; defaultableField: number; } export interface SchemaBInput { fieldB: SchemaCInput; defaultableField?: number; } export const SchemaB: z.ZodType = z.object({ fieldB: z.lazy(() => SchemaC), defaultableField: z.number().optional().default(1), }); export interface SchemaC { fieldC?: SchemaA; } export interface SchemaCInput { fieldC?: SchemaAInput; } export const SchemaC: z.ZodType = z.object({ fieldC: z.lazy(() => SchemaA).optional(), }); export type SchemaZ = z.infer; export const SchemaZ = z.union([ z.object({ fieldZ: z.string(), defField: z.number().optional().default(1), }), z.object({ fieldX: z.boolean(), }), ]); ``` - Real life example provided by @bhapas while working on OpenAPI specs for Integration Assistant APIs Spec: ```yaml components: x-codegen-enabled: true schemas: ESProcessorItem: type: object description: Processor item for the Elasticsearch processor. additionalProperties: $ref: '#/components/schemas/ESProcessorOptions' ESProcessorOptions: type: object description: Processor options for the Elasticsearch processor. properties: on_failure: type: array items: $ref: '#/components/schemas/ESProcessorItem' description: An array of items to execute if the processor fails. ignore_failure: type: boolean description: If true, the processor continues to the next processor if the current processor fails. ignore_missing: type: boolean description: If true, the processor continues to the next processor if the field is missing. if: type: string description: Conditionally execute the processor. tag: type: string description: A tag to assign to the document after processing. additionalProperties: true ``` Generated output: ```ts import type { ZodTypeDef } from 'zod'; import { z } from 'zod'; /** * Processor item for the Elasticsearch processor. */ export interface ESProcessorItem { [key: string]: ESProcessorOptions; } export interface ESProcessorItemInput { [key: string]: ESProcessorOptionsInput; } export const ESProcessorItem: z.ZodType = z .object({}) .catchall(z.lazy(() => ESProcessorOptions)); /** * Processor options for the Elasticsearch processor. */ export interface ESProcessorOptions { /** * An array of items to execute if the processor fails. */ on_failure?: ESProcessorItem[]; /** * If true, the processor continues to the next processor if the current processor fails. */ ignore_failure?: boolean; /** * If true, the processor continues to the next processor if the field is missing. */ ignore_missing?: boolean; /** * Conditionally execute the processor. */ if?: string; /** * A tag to assign to the document after processing. */ tag?: string; [key: string]: unknown; } export interface ESProcessorOptionsInput { /** * An array of items to execute if the processor fails. */ on_failure?: ESProcessorItemInput[]; /** * If true, the processor continues to the next processor if the current processor fails. */ ignore_failure?: boolean; /** * If true, the processor continues to the next processor if the field is missing. */ ignore_missing?: boolean; /** * Conditionally execute the processor. */ if?: string; /** * A tag to assign to the document after processing. */ tag?: string; [key: string]: unknown; } export const ESProcessorOptions: z.ZodType< ESProcessorOptions, ZodTypeDef, ESProcessorOptionsInput > = z .object({ /** * An array of items to execute if the processor fails. */ on_failure: z.array(z.lazy(() => ESProcessorItem)).optional(), /** * If true, the processor continues to the next processor if the current processor fails. */ ignore_failure: z.boolean().optional(), /** * If true, the processor continues to the next processor if the field is missing. */ ignore_missing: z.boolean().optional(), /** * Conditionally execute the processor. */ if: z.string().optional(), /** * A tag to assign to the document after processing. */ tag: z.string().optional(), }) .catchall(z.unknown()); ``` --- .../src/openapi_generator.ts | 1 + .../src/parser/get_generation_context.ts | 4 + .../src/parser/lib/find_refs.ts | 28 +++++ .../src/parser/lib/get_circular_refs.ts | 105 ++++++++++++++++++ .../src/parser/lib/get_imports_map.ts | 30 +---- .../lib/helpers/extract_by_json_pointer.ts | 47 ++++++++ .../src/parser/lib/helpers/has_ref.ts | 19 ++++ .../lib/helpers/is_plain_object_type.ts | 14 +++ .../src/parser/lib/helpers/plain_object.ts | 9 ++ .../lib/{ => helpers}/traverse_object.ts | 0 .../src/parser/lib/normalize_schema.ts | 56 ++++------ .../src/template_service/register_helpers.ts | 37 +++++- .../templates/ts_input_type.handlebars | 84 ++++++++++++++ .../templates/ts_type.handlebars | 84 ++++++++++++++ .../templates/zod_operation_schema.handlebars | 11 +- .../templates/zod_schema_item.handlebars | 13 +-- 16 files changed, 468 insertions(+), 74 deletions(-) create mode 100644 packages/kbn-openapi-generator/src/parser/lib/find_refs.ts create mode 100644 packages/kbn-openapi-generator/src/parser/lib/get_circular_refs.ts create mode 100644 packages/kbn-openapi-generator/src/parser/lib/helpers/extract_by_json_pointer.ts create mode 100644 packages/kbn-openapi-generator/src/parser/lib/helpers/has_ref.ts create mode 100644 packages/kbn-openapi-generator/src/parser/lib/helpers/is_plain_object_type.ts create mode 100644 packages/kbn-openapi-generator/src/parser/lib/helpers/plain_object.ts rename packages/kbn-openapi-generator/src/parser/lib/{ => helpers}/traverse_object.ts (100%) create mode 100644 packages/kbn-openapi-generator/src/template_service/templates/ts_input_type.handlebars create mode 100644 packages/kbn-openapi-generator/src/template_service/templates/ts_type.handlebars diff --git a/packages/kbn-openapi-generator/src/openapi_generator.ts b/packages/kbn-openapi-generator/src/openapi_generator.ts index bdbc8ecec3c979..b5e73613139aa2 100644 --- a/packages/kbn-openapi-generator/src/openapi_generator.ts +++ b/packages/kbn-openapi-generator/src/openapi_generator.ts @@ -100,6 +100,7 @@ export const generate = async (config: GeneratorConfig) => { version: 'Bundle (no version)', }, imports: {}, + circularRefs: new Set(), }); await fs.writeFile(bundle.outFile, result); diff --git a/packages/kbn-openapi-generator/src/parser/get_generation_context.ts b/packages/kbn-openapi-generator/src/parser/get_generation_context.ts index 7f161c0bc76458..2813ff85201e06 100644 --- a/packages/kbn-openapi-generator/src/parser/get_generation_context.ts +++ b/packages/kbn-openapi-generator/src/parser/get_generation_context.ts @@ -13,12 +13,14 @@ import { getImportsMap, ImportsMap } from './lib/get_imports_map'; import { normalizeSchema } from './lib/normalize_schema'; import { NormalizedOperation, OpenApiDocument } from './openapi_types'; import { getInfo } from './lib/get_info'; +import { getCircularRefs } from './lib/get_circular_refs'; export interface GenerationContext { components: OpenAPIV3.ComponentsObject | undefined; operations: NormalizedOperation[]; info: OpenAPIV3.InfoObject; imports: ImportsMap; + circularRefs: Set; } export function getGenerationContext(document: OpenApiDocument): GenerationContext { @@ -28,11 +30,13 @@ export function getGenerationContext(document: OpenApiDocument): GenerationConte const operations = getApiOperationsList(normalizedDocument); const info = getInfo(normalizedDocument); const imports = getImportsMap(normalizedDocument); + const circularRefs = getCircularRefs(normalizedDocument); return { components, operations, info, imports, + circularRefs, }; } diff --git a/packages/kbn-openapi-generator/src/parser/lib/find_refs.ts b/packages/kbn-openapi-generator/src/parser/lib/find_refs.ts new file mode 100644 index 00000000000000..1829c0a5e7ee2c --- /dev/null +++ b/packages/kbn-openapi-generator/src/parser/lib/find_refs.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 { hasRef } from './helpers/has_ref'; +import { traverseObject } from './helpers/traverse_object'; + +/** + * Traverse the OpenAPI document recursively and find all references + * + * @param obj Any object + * @returns A list of external references + */ +export function findRefs(obj: unknown): string[] { + const refs: string[] = []; + + traverseObject(obj, (element) => { + if (hasRef(element)) { + refs.push(element.$ref); + } + }); + + return refs; +} diff --git a/packages/kbn-openapi-generator/src/parser/lib/get_circular_refs.ts b/packages/kbn-openapi-generator/src/parser/lib/get_circular_refs.ts new file mode 100644 index 00000000000000..da9649d5f0c6d2 --- /dev/null +++ b/packages/kbn-openapi-generator/src/parser/lib/get_circular_refs.ts @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { OpenApiDocument } from '../openapi_types'; +import type { PlainObject } from './helpers/plain_object'; +import { extractByJsonPointer } from './helpers/extract_by_json_pointer'; +import { findRefs } from './find_refs'; + +/** + * Extracts circular references from a provided document. + * Currently only local references are supported. + */ +export function getCircularRefs(document: OpenApiDocument): Set { + const localRefs = findLocalRefs(document); + const circularRefs = new Set(); + const resolveLocalRef = (localRef: string): PlainObject => + extractByJsonPointer(document, extractJsonPointer(localRef)); + + // In general references represent a disconnected graph. To find + // all references cycles we need to check each reference. + for (const startRef of new Set(localRefs)) { + const cycleHeadRef = findCycleHeadRef(startRef, resolveLocalRef); + + if (cycleHeadRef) { + circularRefs.add(cycleHeadRef); + } + } + + return circularRefs; +} + +/** + * Searches for a cycle head. A search starts from `startRef` reference. + * + * A cycle head is a first ref in a cycle. If `startRef` inside a cycle + * a cycle head is the starting ref. It can be illustrated as + * + * c1 - c2 - c3 + * / | + * r1 -> r2 -> r3 -> head c4 + * \ | + * c7 - c6 - c5 + * + * On the schema above references `r1`, `r2` and `r3` depend on the cycle but + * aren't part of the cycle. When search is started from them `head` is + * returned. If a search starts from `c3` then `c3` will be returned. + * + * @param startRef A starting point to find a cycle + * @param resolveRef A callback function to resolve an encountered reference. + * It should return a document node the provided ref resolves to. + * @returns a Set representing a cycle or an empty set if a cycle is not found + */ +function findCycleHeadRef( + startRef: string, + resolveRef: (ref: string) => PlainObject +): string | undefined { + let result: string | undefined; + + const visitedRefs = new Set(); + const search = (ref: string): void => { + if (visitedRefs.has(ref)) { + result = ref; + return; + } + + const refNode = resolveRef(ref); + const nextRefs = findLocalRefs(refNode); + + visitedRefs.add(ref); + nextRefs.forEach(search); + visitedRefs.delete(ref); + }; + + search(startRef); + + return result; +} + +/** + * Finds local references + */ +function findLocalRefs(obj: unknown): string[] { + return findRefs(obj).filter((ref) => isLocalRef(ref)); +} + +/** + * Checks whether the provided ref is local. + * Local references start with `#/` + */ +function isLocalRef(ref: string): boolean { + return ref.startsWith('#/'); +} + +/** + * Extracts a JSON Pointer from a local reference + * by getting rid of the leading slash + */ +function extractJsonPointer(ref: string): string { + return ref.substring(1); +} diff --git a/packages/kbn-openapi-generator/src/parser/lib/get_imports_map.ts b/packages/kbn-openapi-generator/src/parser/lib/get_imports_map.ts index c2259052e0cb6f..634ac82aaae8cc 100644 --- a/packages/kbn-openapi-generator/src/parser/lib/get_imports_map.ts +++ b/packages/kbn-openapi-generator/src/parser/lib/get_imports_map.ts @@ -8,7 +8,7 @@ import { uniq } from 'lodash'; import type { OpenApiDocument } from '../openapi_types'; -import { traverseObject } from './traverse_object'; +import { findRefs } from './find_refs'; export interface ImportsMap { [importPath: string]: string[]; @@ -37,31 +37,3 @@ export const getImportsMap = (parsedSchema: OpenApiDocument): ImportsMap => { return importMap; }; - -/** - * Check if an object has a $ref property - * - * @param obj Any object - * @returns True if the object has a $ref property - */ -const hasRef = (obj: unknown): obj is { $ref: string } => { - return typeof obj === 'object' && obj !== null && '$ref' in obj; -}; - -/** - * Traverse the OpenAPI document recursively and find all references - * - * @param obj Any object - * @returns A list of external references - */ -function findRefs(obj: unknown): string[] { - const refs: string[] = []; - - traverseObject(obj, (element) => { - if (hasRef(element)) { - refs.push(element.$ref); - } - }); - - return refs; -} diff --git a/packages/kbn-openapi-generator/src/parser/lib/helpers/extract_by_json_pointer.ts b/packages/kbn-openapi-generator/src/parser/lib/helpers/extract_by_json_pointer.ts new file mode 100644 index 00000000000000..bdfe59965b576c --- /dev/null +++ b/packages/kbn-openapi-generator/src/parser/lib/helpers/extract_by_json_pointer.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { PlainObject } from './plain_object'; +import { isPlainObjectType } from './is_plain_object_type'; + +/** + * Extract a node from a document using a provided [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901). + * + * JSON Pointer is the second part in [JSON Reference](https://datatracker.ietf.org/doc/html/draft-pbryan-zyp-json-ref-03). + * For example an object `{ $ref: "./some-file.yaml#/components/schemas/MySchema"}` is a reference node. + * Where `/components/schemas/MySchema` is a JSON pointer. `./some-file.yaml` is a document reference. + * Yaml shares the same JSON reference standard and basically can be considered just as a different + * JS Object serialization format. See OpenAPI [Using $ref](https://swagger.io/docs/specification/using-ref/) for more information. + * + * @param document a document containing node to resolve by using the pointer + * @param pointer a JSON Pointer + * @returns resolved document node (it's always a JS object) + */ +export function extractByJsonPointer(document: unknown, pointer: string): PlainObject { + if (!pointer.startsWith('/')) { + throw new Error('$ref pointer must start with a leading slash'); + } + + if (!isPlainObjectType(document)) { + throw new Error('document must be an object'); + } + + let target = document; + + for (const segment of pointer.slice(1).split('/')) { + const nextTarget = target[segment]; + + if (!isPlainObjectType(nextTarget)) { + throw new Error(`JSON Pointer "${pointer}" is not found in "${JSON.stringify(document)}"`); + } + + target = nextTarget; + } + + return target; +} diff --git a/packages/kbn-openapi-generator/src/parser/lib/helpers/has_ref.ts b/packages/kbn-openapi-generator/src/parser/lib/helpers/has_ref.ts new file mode 100644 index 00000000000000..4457665070f7b3 --- /dev/null +++ b/packages/kbn-openapi-generator/src/parser/lib/helpers/has_ref.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 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 { NormalizedReferenceObject } from '../../openapi_types'; + +/** + * Check if an object has a $ref property + * + * @param obj Any object + * @returns True if the object has a $ref property + */ +export function hasRef(obj: unknown): obj is NormalizedReferenceObject { + return typeof obj === 'object' && obj !== null && '$ref' in obj; +} diff --git a/packages/kbn-openapi-generator/src/parser/lib/helpers/is_plain_object_type.ts b/packages/kbn-openapi-generator/src/parser/lib/helpers/is_plain_object_type.ts new file mode 100644 index 00000000000000..c3612443800e9d --- /dev/null +++ b/packages/kbn-openapi-generator/src/parser/lib/helpers/is_plain_object_type.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isPlainObject } from 'lodash'; +import type { PlainObject } from './plain_object'; + +export function isPlainObjectType(maybeObj: unknown): maybeObj is PlainObject { + return isPlainObject(maybeObj); +} diff --git a/packages/kbn-openapi-generator/src/parser/lib/helpers/plain_object.ts b/packages/kbn-openapi-generator/src/parser/lib/helpers/plain_object.ts new file mode 100644 index 00000000000000..8a3fead0f8b807 --- /dev/null +++ b/packages/kbn-openapi-generator/src/parser/lib/helpers/plain_object.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type PlainObject = Record; diff --git a/packages/kbn-openapi-generator/src/parser/lib/traverse_object.ts b/packages/kbn-openapi-generator/src/parser/lib/helpers/traverse_object.ts similarity index 100% rename from packages/kbn-openapi-generator/src/parser/lib/traverse_object.ts rename to packages/kbn-openapi-generator/src/parser/lib/helpers/traverse_object.ts diff --git a/packages/kbn-openapi-generator/src/parser/lib/normalize_schema.ts b/packages/kbn-openapi-generator/src/parser/lib/normalize_schema.ts index 0ed02a28585ebe..d082b9a96dc444 100644 --- a/packages/kbn-openapi-generator/src/parser/lib/normalize_schema.ts +++ b/packages/kbn-openapi-generator/src/parser/lib/normalize_schema.ts @@ -7,41 +7,31 @@ */ import { OpenAPIV3 } from 'openapi-types'; -import { NormalizedReferenceObject } from '../openapi_types'; -import { traverseObject } from './traverse_object'; - -/** - * Check if an object has a $ref property - * - * @param obj Any object - * @returns True if the object has a $ref property - */ -const hasRef = (obj: unknown): obj is NormalizedReferenceObject => { - return typeof obj === 'object' && obj !== null && '$ref' in obj; -}; - -const stringIsUrl = (str: string) => { - try { - new URL(str); - return true; - } catch { - return false; - } -}; - -export function normalizeSchema(schema: OpenAPIV3.Document) { +import { URL } from 'node:url'; +import { traverseObject } from './helpers/traverse_object'; +import { hasRef } from './helpers/has_ref'; + +function isUrl(maybeUrl: string): boolean { + return URL.canParse(maybeUrl); +} + +export function normalizeSchema(schema: OpenAPIV3.Document): OpenAPIV3.Document { traverseObject(schema, (element) => { - if (hasRef(element)) { - if (stringIsUrl(element.$ref)) { - throw new Error(`URL references are not supported: ${element.$ref}`); - } - const referenceName = element.$ref.split('/').pop(); - if (!referenceName) { - throw new Error(`Cannot parse reference name: ${element.$ref}`); - } - - element.referenceName = referenceName; + if (!hasRef(element)) { + return; + } + + if (isUrl(element.$ref)) { + throw new Error(`URL references are not supported: ${element.$ref}`); } + + const referenceName = element.$ref.split('/').pop(); + + if (!referenceName) { + throw new Error(`Cannot parse reference name: ${element.$ref}`); + } + + element.referenceName = referenceName; }); return schema; diff --git a/packages/kbn-openapi-generator/src/template_service/register_helpers.ts b/packages/kbn-openapi-generator/src/template_service/register_helpers.ts index c676ae869c7ab5..55f2d9d60f37a0 100644 --- a/packages/kbn-openapi-generator/src/template_service/register_helpers.ts +++ b/packages/kbn-openapi-generator/src/template_service/register_helpers.ts @@ -7,6 +7,7 @@ */ import type Handlebars from '@kbn/handlebars'; +import { HelperOptions } from 'handlebars'; import { snakeCase, camelCase } from 'lodash'; export function registerHelpers(handlebarsInstance: typeof Handlebars) { @@ -47,13 +48,43 @@ export function registerHelpers(handlebarsInstance: typeof Handlebars) { handlebarsInstance.registerHelper('isUnknown', (val: object) => { return !('type' in val || '$ref' in val || 'anyOf' in val || 'oneOf' in val || 'allOf' in val); }); - handlebarsInstance.registerHelper('startsWithSpecialChar', (val: string) => { - return /^[^a-zA-Z0-9]/.test(val); - }); handlebarsInstance.registerHelper( 'replace', (val: string, searchValue: string, replaceValue: string) => { return val.replace(searchValue, replaceValue); } ); + + /** + * Checks whether provided reference is a known circular reference or a part of circular chain. + * + * It's expected that `context.recursiveRefs` has been filled by the parser. + */ + handlebarsInstance.registerHelper('isCircularRef', (ref: string, options: HelperOptions) => { + if (!options.data?.root?.circularRefs) { + return false; + } + + const circularRefs: Set = options.data.root.circularRefs; + + return circularRefs.has(ref); + }); + + /** + * Checks whether provided schema is circular or a part of the circular chain. + * + * It's expected that `context.circularRefs` has been filled by the parser. + */ + handlebarsInstance.registerHelper( + 'isCircularSchema', + (schemaName: string, options: HelperOptions) => { + if (!options.data?.root?.circularRefs) { + return false; + } + + const circularRefs: Set = options.data.root.circularRefs; + + return circularRefs.has(`#/components/schemas/${schemaName}`); + } + ); } diff --git a/packages/kbn-openapi-generator/src/template_service/templates/ts_input_type.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/ts_input_type.handlebars new file mode 100644 index 00000000000000..453e4cdf452d52 --- /dev/null +++ b/packages/kbn-openapi-generator/src/template_service/templates/ts_input_type.handlebars @@ -0,0 +1,84 @@ +{{~#if type~}} + {{~> (concat "type_" type)~}} +{{~/if~}} + +{{~#if $ref~}} + {{referenceName}}Input + {{~#if nullable}} | null {{/if~}} +{{~/if~}} + +{{~#if allOf~}} + {{~#each allOf~}} + {{~> ts_input_type ~}} + {{~#unless @last~}}&{{~/unless~}} + {{~/each~}} +{{~/if~}} + +{{~#if anyOf~}} + {{~#each anyOf~}} + {{~> ts_input_type ~}} + {{~#unless @last~}}|{{~/unless~}} + {{~/each~}} +{{~/if~}} + +{{~#if oneOf~}} + {{~#each oneOf~}} + {{~> ts_input_type ~}} + {{~#unless @last~}}|{{~/unless~}} + {{~/each~}} +{{~/if~}} + +{{#if (isUnknown .)}} +unknown +{{/if}} + +{{~#*inline "type_array"~}} + ({{~> ts_input_type items ~}})[] +{{~/inline~}} + +{{~#*inline "type_boolean"~}} + boolean +{{~/inline~}} + +{{~#*inline "type_integer"~}} + number +{{~/inline~}} + +{{~#*inline "type_number"~}} + number +{{~/inline~}} + +{{~#*inline "type_object"~}} + {{~#if (eq x-modify "required")}} Required< {{/if~}} + {{~#if (eq x-modify "partial")}} Partial< {{/if~}} + { + {{#each properties}} + {{#if description}} + /** + * {{{description}}} + */ + {{/if}} + '{{@key}}'{{~#unless (includes ../required @key)}}?{{/unless~}}: {{> ts_input_type }}; + {{/each}} + {{~#if additionalProperties}} + {{~#if (eq additionalProperties true)~}} + [key: string]: unknown; + {{~else~}} + [key: string]: {{> ts_input_type additionalProperties}}; + {{~/if~}} + {{~/if~}} + } + {{~#if (eq x-modify "partial")}} > {{/if~}} + {{~#if (eq x-modify "required")}} > {{/if~}} +{{~/inline~}} + +{{~#*inline "type_string"~}} + {{~#if enum~}} + {{~#each enum~}} + '{{.}}' + {{~#unless @last~}}|{{~/unless~}} + {{~/each~}} + {{~else~}} + string + {{~/if~}} +{{~/inline~}} diff --git a/packages/kbn-openapi-generator/src/template_service/templates/ts_type.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/ts_type.handlebars new file mode 100644 index 00000000000000..5017af3aa5df05 --- /dev/null +++ b/packages/kbn-openapi-generator/src/template_service/templates/ts_type.handlebars @@ -0,0 +1,84 @@ +{{~#if type~}} + {{~> (concat "type_" type)~}} +{{~/if~}} + +{{~#if $ref~}} + {{referenceName}} + {{~#if nullable}} | null {{/if~}} +{{~/if~}} + +{{~#if allOf~}} + {{~#each allOf~}} + {{~> ts_type ~}} + {{~#unless @last~}}&{{~/unless~}} + {{~/each~}} +{{~/if~}} + +{{~#if anyOf~}} + {{~#each anyOf~}} + {{~> ts_type ~}} + {{~#unless @last~}}|{{~/unless~}} + {{~/each~}} +{{~/if~}} + +{{~#if oneOf~}} + {{~#each oneOf~}} + {{~> ts_type ~}} + {{~#unless @last~}}|{{~/unless~}} + {{~/each~}} +{{~/if~}} + +{{#if (isUnknown .)}} +unknown +{{/if}} + +{{~#*inline "type_array"~}} + ({{~> ts_type items ~}})[] +{{~/inline~}} + +{{~#*inline "type_boolean"~}} + boolean +{{~/inline~}} + +{{~#*inline "type_integer"~}} + number +{{~/inline~}} + +{{~#*inline "type_number"~}} + number +{{~/inline~}} + +{{~#*inline "type_object"~}} + {{~#if (eq x-modify "required")}} Required< {{/if~}} + {{~#if (eq x-modify "partial")}} Partial< {{/if~}} + { + {{#each properties}} + {{#if description}} + /** + * {{{description}}} + */ + {{/if}} + '{{@key}}'{{~#unless (or (includes ../required @key) (defined default))}}?{{/unless~}}: {{> ts_type }}; + {{/each}} + {{~#if additionalProperties}} + {{~#if (eq additionalProperties true)~}} + [key: string]: unknown; + {{~else~}} + [key: string]: {{> ts_type additionalProperties}}; + {{~/if~}} + {{~/if~}} + } + {{~#if (eq x-modify "partial")}} > {{/if~}} + {{~#if (eq x-modify "required")}} > {{/if~}} +{{~/inline~}} + +{{~#*inline "type_string"~}} + {{~#if enum~}} + {{~#each enum~}} + '{{.}}' + {{~#unless @last~}}|{{~/unless~}} + {{~/each~}} + {{~else~}} + string + {{~/if~}} +{{~/inline~}} diff --git a/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars index 30bc647b1fb252..6e5d21363a5ae1 100644 --- a/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars +++ b/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars @@ -7,8 +7,9 @@ {{> disclaimer}} -import { z } from "zod"; -import { requiredOptional, isValidDateMath, ArrayFromString, BooleanFromString } from "@kbn/zod-helpers" +import type { ZodTypeDef } from 'zod'; +import { z } from 'zod'; +import { requiredOptional, isValidDateMath, ArrayFromString, BooleanFromString } from '@kbn/zod-helpers'; {{#each imports}} import { @@ -25,8 +26,14 @@ import { {{/if}} */ {{/if}} +{{#if (isCircularSchema @key)}} +export type {{@key}} = {{> ts_type}}; +export type {{@key}}Input = {{> ts_input_type }}; +export const {{@key}}: z.ZodType<{{@key}}, ZodTypeDef, {{@key}}Input> = {{> zod_schema_item }}; +{{else}} export type {{@key}} = z.infer; export const {{@key}} = {{> zod_schema_item}}; +{{/if}} {{#if enum}} {{#unless (isSingle enum)}} export type {{@key}}Enum = typeof {{@key}}.enum; diff --git a/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars index 29d4453da4d7be..7ad0abaf1cad89 100644 --- a/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars +++ b/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars @@ -6,7 +6,11 @@ {{~/if~}} {{~#if $ref~}} - {{referenceName}} + {{~#if (isCircularRef $ref)~}} + z.lazy(() => {{referenceName}}) + {{~else~}} + {{referenceName}} + {{~/if~}} {{~#if nullable}}.nullable(){{/if~}} {{~#if (eq requiredBool false)}}.optional(){{/if~}} {{~#if (defined default)}}.default({{{toJSON default}}}){{/if~}} @@ -87,11 +91,7 @@ z.unknown() * {{{description}}} */ {{/if}} - {{#if (startsWithSpecialChar @key)}} - '{{@key}}': {{> zod_schema_item requiredBool=(includes ../required @key)}}, - {{else}} - {{@key}}: {{> zod_schema_item requiredBool=(includes ../required @key)}}, - {{/if}} + '{{@key}}':{{~> zod_schema_item requiredBool=(includes ../required @key)~}}, {{/each}} }) {{~#if (eq additionalProperties false)}}.strict(){{/if~}} @@ -127,4 +127,3 @@ z.unknown() {{~#if pattern}}.regex(/{{pattern}}/){{/if~}} {{~/if~}} {{~/inline~}} - From a021e48e2b236852dae5f9602e21b1c9de300ac0 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 18 Jun 2024 11:50:35 -0700 Subject: [PATCH 054/123] [OAS] Refresh connectors API document (#186141) --- .../plugins/actions/docs/openapi/bundled.json | 1700 ++++++++--------- .../plugins/actions/docs/openapi/bundled.yaml | 1174 ++++++------ .../docs/openapi/bundled_serverless.json | 388 ++-- .../docs/openapi/bundled_serverless.yaml | 300 ++- .../components/parameters/action_id.yaml | 3 +- .../components/parameters/connector_id.yaml | 3 +- .../components/parameters/space_id.yaml | 3 +- .../openapi/components/responses/400.yaml | 9 +- .../openapi/components/responses/401.yaml | 6 +- .../openapi/components/responses/404.yaml | 9 +- .../config_properties_cases_webhook.yaml | 21 +- .../schemas/config_properties_email.yaml | 15 +- .../schemas/config_properties_index.yaml | 5 +- .../schemas/config_properties_pagerduty.yaml | 8 +- .../schemas/config_properties_webhook.yaml | 7 +- .../schemas/config_properties_xmatters.yaml | 5 +- ...nnector_response_properties_serverlog.yaml | 5 +- .../components/schemas/connector_types.yaml | 3 +- .../create_connector_request_bedrock.yaml | 6 +- ...reate_connector_request_cases_webhook.yaml | 6 +- .../create_connector_request_d3security.yaml | 6 +- .../create_connector_request_email.yaml | 6 +- .../create_connector_request_gemini.yaml | 6 +- .../create_connector_request_genai.yaml | 6 +- .../create_connector_request_index.yaml | 6 +- .../create_connector_request_jira.yaml | 6 +- .../create_connector_request_opsgenie.yaml | 6 +- .../create_connector_request_pagerduty.yaml | 6 +- .../create_connector_request_resilient.yaml | 6 +- .../create_connector_request_sentinelone.yaml | 6 +- .../create_connector_request_serverlog.yaml | 6 +- .../create_connector_request_servicenow.yaml | 6 +- ...ate_connector_request_servicenow_itom.yaml | 6 +- ...eate_connector_request_servicenow_sir.yaml | 6 +- .../create_connector_request_slack_api.yaml | 6 +- ...reate_connector_request_slack_webhook.yaml | 6 +- .../create_connector_request_swimlane.yaml | 6 +- .../create_connector_request_teams.yaml | 6 +- .../create_connector_request_tines.yaml | 6 +- .../create_connector_request_torq.yaml | 6 +- .../create_connector_request_webhook.yaml | 6 +- .../create_connector_request_xmatters.yaml | 6 +- .../components/schemas/is_deprecated.yaml | 3 +- .../schemas/is_missing_secrets.yaml | 3 +- .../components/schemas/is_preconfigured.yaml | 3 +- .../components/schemas/is_system_action.yaml | 3 +- .../schemas/referenced_by_count.yaml | 3 +- ...un_connector_params_trigger_pagerduty.yaml | 9 +- ...run_connector_subaction_closeincident.yaml | 6 +- .../run_connector_subaction_createalert.yaml | 3 +- ...connector_subaction_fieldsbyissuetype.yaml | 3 +- .../run_connector_subaction_getincident.yaml | 3 +- .../run_connector_subaction_issue.yaml | 3 +- ...pdate_connector_request_cases_webhook.yaml | 3 +- .../update_connector_request_swimlane.yaml | 3 +- .../actions/docs/openapi/entrypoint.yaml | 23 +- .../docs/openapi/entrypoint_serverless.yaml | 7 +- .../openapi/paths/api@actions@connector.yaml | 2 +- .../api@actions@connector@{connectorid}.yaml | 11 +- ...ions@connector@{connectorid}@_execute.yaml | 2 +- .../paths/api@actions@connector_types.yaml | 23 +- .../openapi/paths/api@actions@connectors.yaml | 2 +- .../paths/s@{spaceid}@api@actions.yaml | 4 +- ...paceid}@api@actions@action@{actionid}.yaml | 6 +- ...pi@actions@action@{actionid}@_execute.yaml | 2 +- .../s@{spaceid}@api@actions@connector.yaml | 2 +- ...}@api@actions@connector@{connectorid}.yaml | 11 +- ...ions@connector@{connectorid}@_execute.yaml | 2 +- ...{spaceid}@api@actions@connector_types.yaml | 20 +- .../s@{spaceid}@api@actions@connectors.yaml | 2 +- ...paceid}@api@actions@list_action_types.yaml | 5 +- 71 files changed, 1656 insertions(+), 2324 deletions(-) diff --git a/x-pack/plugins/actions/docs/openapi/bundled.json b/x-pack/plugins/actions/docs/openapi/bundled.json index ae6e418dc775e2..df93f77a5ab203 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.json +++ b/x-pack/plugins/actions/docs/openapi/bundled.json @@ -1,5 +1,5 @@ { - "openapi": "3.1.0", + "openapi": "3.0.3", "info": { "title": "Connectors", "description": "OpenAPI schema for Connectors endpoints", @@ -32,16 +32,20 @@ } ], "paths": { - "/api/actions/connector": { + "/s/{spaceId}/api/actions/connector": { "post": { - "summary": "Creates a connector.", - "operationId": "createConnector", + "summary": "Create a connector", + "operationId": "createConnectorWithSpaceId", + "description": "You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", "tags": [ "connectors" ], "parameters": [ { "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" } ], "requestBody": { @@ -99,16 +103,20 @@ } } }, - "/api/actions/connector/{connectorId}": { + "/s/{spaceId}/api/actions/connector/{connectorId}": { "get": { - "summary": "Retrieves a connector by ID.", - "operationId": "getConnector", + "summary": "Get connector information", + "operationId": "getConnectorWithSpaceId", + "description": "You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", "tags": [ "connectors" ], "parameters": [ { "$ref": "#/components/parameters/connector_id" + }, + { + "$ref": "#/components/parameters/space_id" } ], "responses": { @@ -136,8 +144,9 @@ } }, "delete": { - "summary": "Deletes a connector.", - "operationId": "deleteConnector", + "summary": "Delete a connector", + "operationId": "deleteConnectorWithSpaceId", + "description": "You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. WARNING: When you delete a connector, it cannot be recovered.\n", "tags": [ "connectors" ], @@ -147,6 +156,9 @@ }, { "$ref": "#/components/parameters/connector_id" + }, + { + "$ref": "#/components/parameters/space_id" } ], "responses": { @@ -162,8 +174,9 @@ } }, "post": { - "summary": "Creates a connector.", - "operationId": "createConnectorId", + "summary": "Create a connector", + "operationId": "createConnectorIdWithSpaceId", + "description": "You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", "tags": [ "connectors" ], @@ -171,16 +184,17 @@ { "$ref": "#/components/parameters/kbn_xsrf" }, + { + "$ref": "#/components/parameters/space_id" + }, { "in": "path", "name": "connectorId", - "description": "A UUID v1 or v4 identifier for the connector. If you omit this parameter, an identifier is randomly generated.\n", + "description": "A UUID v1 or v4 identifier for the connector. If you omit this parameter, an identifier is randomly generated.", "required": true, "schema": { "type": "string", - "examples": [ - "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" - ] + "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" } } ], @@ -221,8 +235,9 @@ } }, "put": { - "summary": "Updates the attributes for a connector.", - "operationId": "updateConnector", + "summary": "Update a connector", + "operationId": "updateConnectorWithSpaceId", + "description": "You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", "tags": [ "connectors" ], @@ -232,6 +247,9 @@ }, { "$ref": "#/components/parameters/connector_id" + }, + { + "$ref": "#/components/parameters/space_id" } ], "requestBody": { @@ -272,10 +290,138 @@ } } }, - "/api/actions/connector/{connectorId}/_execute": { + "/s/{spaceId}/api/actions/connectors": { + "get": { + "summary": "Get all connectors", + "operationId": "getConnectorsWithSpaceId", + "description": "You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", + "tags": [ + "connectors" + ], + "parameters": [ + { + "$ref": "#/components/parameters/space_id" + } + ], + "responses": { + "200": { + "description": "Indicates a successful call.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/connector_response_properties" + } + }, + "examples": { + "getConnectorsResponse": { + "$ref": "#/components/examples/get_connectors_response" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/s/{spaceId}/api/actions/connector_types": { + "get": { + "summary": "Get all connector types", + "operationId": "getConnectorTypesWithSpaceId", + "description": "You do not need any Kibana feature privileges to run this API.\n", + "tags": [ + "connectors" + ], + "parameters": [ + { + "$ref": "#/components/parameters/space_id" + }, + { + "in": "query", + "name": "feature_id", + "description": "A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases).", + "schema": { + "$ref": "#/components/schemas/features" + } + } + ], + "responses": { + "200": { + "description": "Indicates a successful call.", + "content": { + "application/json": { + "schema": { + "title": "Get connector types response body properties", + "description": "The properties vary for each connector type.", + "type": "array", + "items": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Indicates whether the connector type is enabled in Kibana.", + "example": true + }, + "enabled_in_config": { + "type": "boolean", + "description": "Indicates whether the connector type is enabled in the Kibana `.yml` file.", + "example": true + }, + "enabled_in_license": { + "type": "boolean", + "description": "Indicates whether the connector is enabled in the license.", + "example": true + }, + "id": { + "$ref": "#/components/schemas/connector_types" + }, + "minimum_license_required": { + "type": "string", + "description": "The license that is required to use the connector type.", + "example": "basic" + }, + "name": { + "type": "string", + "description": "The name of the connector type.", + "example": "Index" + }, + "supported_feature_ids": { + "type": "array", + "description": "The Kibana features that are supported by the connector type.", + "items": { + "$ref": "#/components/schemas/features" + }, + "example": [ + "alerting", + "uptime", + "siem" + ] + } + } + } + }, + "examples": { + "getConnectorTypesResponse": { + "$ref": "#/components/examples/get_connector_types_response" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/s/{spaceId}/api/actions/connector/{connectorId}/_execute": { "post": { - "summary": "Runs a connector.", - "operationId": "runConnector", + "summary": "Run a connector", + "operationId": "runConnectorWithSpaceId", "description": "You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. If you use an index connector, you must also have `all`, `create`, `index`, or `write` indices privileges.\n", "tags": [ "connectors" @@ -286,6 +432,9 @@ }, { "$ref": "#/components/parameters/connector_id" + }, + { + "$ref": "#/components/parameters/space_id" } ], "requestBody": { @@ -296,21 +445,12 @@ "$ref": "#/components/schemas/run_connector_request" }, "examples": { - "runCasesWebhookConnectorRequest": { - "$ref": "#/components/examples/run_cases_webhook_connector_request" - }, - "runEmailConnectorRequest": { - "$ref": "#/components/examples/run_email_connector_request" - }, "runIndexConnectorRequest": { "$ref": "#/components/examples/run_index_connector_request" }, "runJiraConnectorRequest": { "$ref": "#/components/examples/run_jira_connector_request" }, - "runPagerDutyConnectorRequest": { - "$ref": "#/components/examples/run_pagerduty_connector_request" - }, "runServerLogConnectorRequest": { "$ref": "#/components/examples/run_server_log_connector_request" }, @@ -359,6 +499,12 @@ } ] }, + "message": { + "type": "string" + }, + "service_message": { + "type": "string" + }, "status": { "type": "string", "description": "The status of the action.", @@ -370,21 +516,12 @@ } }, "examples": { - "runCasesWebhookConnectorResponse": { - "$ref": "#/components/examples/run_cases_webhook_connector_response" - }, - "runEmailConnectorResponse": { - "$ref": "#/components/examples/run_email_connector_response" - }, "runIndexConnectorResponse": { "$ref": "#/components/examples/run_index_connector_response" }, "runJiraConnectorResponse": { "$ref": "#/components/examples/run_jira_connector_response" }, - "runPagerDutyConnectorResponse": { - "$ref": "#/components/examples/run_pagerduty_connector_response" - }, "runServerLogConnectorResponse": { "$ref": "#/components/examples/run_server_log_connector_response" }, @@ -407,27 +544,62 @@ } } }, - "/api/actions/connectors": { - "get": { - "summary": "Retrieves all connectors.", - "operationId": "getConnectors", + "/api/actions/connector": { + "post": { + "summary": "Create a connector", + "operationId": "createConnector", "tags": [ "connectors" ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/create_connector_request" + }, + "examples": { + "createEmailConnectorRequest": { + "$ref": "#/components/examples/create_email_connector_request" + }, + "createIndexConnectorRequest": { + "$ref": "#/components/examples/create_index_connector_request" + }, + "createWebhookConnectorRequest": { + "$ref": "#/components/examples/create_webhook_connector_request" + }, + "createXmattersConnectorRequest": { + "$ref": "#/components/examples/create_xmatters_connector_request" + } + } + } + } + }, "responses": { "200": { "description": "Indicates a successful call.", "content": { "application/json": { "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/connector_response_properties" - } + "$ref": "#/components/schemas/connector_response_properties" }, "examples": { - "getConnectorsResponse": { - "$ref": "#/components/examples/get_connectors_response" + "createEmailConnectorResponse": { + "$ref": "#/components/examples/create_email_connector_response" + }, + "createIndexConnectorResponse": { + "$ref": "#/components/examples/create_index_connector_response" + }, + "createWebhookConnectorResponse": { + "$ref": "#/components/examples/create_webhook_connector_response" + }, + "createXmattersConnectorResponse": { + "$ref": "#/components/examples/create_xmatters_connector_response" } } } @@ -439,195 +611,16 @@ } } }, - "/api/actions/connector_types": { + "/api/actions/connector/{connectorId}": { "get": { - "summary": "Retrieves a list of all connector types.", - "operationId": "getConnectorTypes", + "summary": "Get a connector information", + "operationId": "getConnector", "tags": [ "connectors" ], "parameters": [ { - "in": "query", - "name": "feature_id", - "description": "A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases).", - "schema": { - "$ref": "#/components/schemas/features" - } - } - ], - "responses": { - "200": { - "description": "Indicates a successful call.", - "content": { - "application/json": { - "schema": { - "title": "Get connector types response body properties", - "description": "The properties vary for each connector type.", - "type": "array", - "items": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Indicates whether the connector type is enabled in Kibana.", - "examples": [ - true - ] - }, - "enabled_in_config": { - "type": "boolean", - "description": "Indicates whether the connector type is enabled in the Kibana configuration file.", - "examples": [ - true - ] - }, - "enabled_in_license": { - "type": "boolean", - "description": "Indicates whether the connector is enabled in the license.", - "examples": [ - true - ] - }, - "id": { - "$ref": "#/components/schemas/connector_types" - }, - "is_system_action_type": { - "type": "boolean", - "examples": [ - false - ] - }, - "minimum_license_required": { - "type": "string", - "description": "The license that is required to use the connector type.", - "examples": [ - "basic" - ] - }, - "name": { - "type": "string", - "description": "The name of the connector type.", - "examples": [ - "Index" - ] - }, - "supported_feature_ids": { - "type": "array", - "description": "The features that are supported by the connector type.", - "items": { - "$ref": "#/components/schemas/features" - }, - "examples": [ - [ - "alerting", - "cases", - "siem" - ] - ] - } - } - } - }, - "examples": { - "getConnectorTypesServerlessResponse": { - "$ref": "#/components/examples/get_connector_types_generativeai_response" - } - } - } - } - }, - "401": { - "$ref": "#/components/responses/401" - } - } - } - }, - "/s/{spaceId}/api/actions/connector": { - "post": { - "summary": "Creates a connector.", - "operationId": "createConnectorWithSpaceId", - "description": "You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", - "tags": [ - "connectors" - ], - "parameters": [ - { - "$ref": "#/components/parameters/kbn_xsrf" - }, - { - "$ref": "#/components/parameters/space_id" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/create_connector_request" - }, - "examples": { - "createEmailConnectorRequest": { - "$ref": "#/components/examples/create_email_connector_request" - }, - "createIndexConnectorRequest": { - "$ref": "#/components/examples/create_index_connector_request" - }, - "createWebhookConnectorRequest": { - "$ref": "#/components/examples/create_webhook_connector_request" - }, - "createXmattersConnectorRequest": { - "$ref": "#/components/examples/create_xmatters_connector_request" - } - } - } - } - }, - "responses": { - "200": { - "description": "Indicates a successful call.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/connector_response_properties" - }, - "examples": { - "createEmailConnectorResponse": { - "$ref": "#/components/examples/create_email_connector_response" - }, - "createIndexConnectorResponse": { - "$ref": "#/components/examples/create_index_connector_response" - }, - "createWebhookConnectorResponse": { - "$ref": "#/components/examples/create_webhook_connector_response" - }, - "createXmattersConnectorResponse": { - "$ref": "#/components/examples/create_xmatters_connector_response" - } - } - } - } - }, - "401": { - "$ref": "#/components/responses/401" - } - } - } - }, - "/s/{spaceId}/api/actions/connector/{connectorId}": { - "get": { - "summary": "Retrieves a connector by ID.", - "operationId": "getConnectorWithSpaceId", - "description": "You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", - "tags": [ - "connectors" - ], - "parameters": [ - { - "$ref": "#/components/parameters/connector_id" - }, - { - "$ref": "#/components/parameters/space_id" + "$ref": "#/components/parameters/connector_id" } ], "responses": { @@ -655,9 +648,8 @@ } }, "delete": { - "summary": "Deletes a connector.", - "operationId": "deleteConnectorWithSpaceId", - "description": "You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. WARNING: When you delete a connector, it cannot be recovered.\n", + "summary": "Delete a connector", + "operationId": "deleteConnector", "tags": [ "connectors" ], @@ -667,9 +659,6 @@ }, { "$ref": "#/components/parameters/connector_id" - }, - { - "$ref": "#/components/parameters/space_id" } ], "responses": { @@ -685,9 +674,8 @@ } }, "post": { - "summary": "Creates a connector.", - "operationId": "createConnectorIdWithSpaceId", - "description": "You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", + "summary": "Create a connector", + "operationId": "createConnectorId", "tags": [ "connectors" ], @@ -695,19 +683,14 @@ { "$ref": "#/components/parameters/kbn_xsrf" }, - { - "$ref": "#/components/parameters/space_id" - }, { "in": "path", "name": "connectorId", - "description": "A UUID v1 or v4 identifier for the connector. If you omit this parameter, an identifier is randomly generated.", + "description": "A UUID v1 or v4 identifier for the connector. If you omit this parameter, an identifier is randomly generated.\n", "required": true, "schema": { "type": "string", - "examples": [ - "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" - ] + "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" } } ], @@ -748,9 +731,8 @@ } }, "put": { - "summary": "Updates the attributes for a connector.", - "operationId": "updateConnectorWithSpaceId", - "description": "You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", + "summary": "Update a connector", + "operationId": "updateConnector", "tags": [ "connectors" ], @@ -760,9 +742,6 @@ }, { "$ref": "#/components/parameters/connector_id" - }, - { - "$ref": "#/components/parameters/space_id" } ], "requestBody": { @@ -803,150 +782,10 @@ } } }, - "/s/{spaceId}/api/actions/connectors": { - "get": { - "summary": "Retrieves all connectors.", - "operationId": "getConnectorsWithSpaceId", - "description": "You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges.\n", - "tags": [ - "connectors" - ], - "parameters": [ - { - "$ref": "#/components/parameters/space_id" - } - ], - "responses": { - "200": { - "description": "Indicates a successful call.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/connector_response_properties" - } - }, - "examples": { - "getConnectorsResponse": { - "$ref": "#/components/examples/get_connectors_response" - } - } - } - } - }, - "401": { - "$ref": "#/components/responses/401" - } - } - } - }, - "/s/{spaceId}/api/actions/connector_types": { - "get": { - "summary": "Retrieves a list of all connector types.", - "operationId": "getConnectorTypesWithSpaceId", - "description": "You do not need any Kibana feature privileges to run this API.\n", - "tags": [ - "connectors" - ], - "parameters": [ - { - "$ref": "#/components/parameters/space_id" - }, - { - "in": "query", - "name": "feature_id", - "description": "A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases).", - "schema": { - "$ref": "#/components/schemas/features" - } - } - ], - "responses": { - "200": { - "description": "Indicates a successful call.", - "content": { - "application/json": { - "schema": { - "title": "Get connector types response body properties", - "description": "The properties vary for each connector type.", - "type": "array", - "items": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Indicates whether the connector type is enabled in Kibana.", - "examples": [ - true - ] - }, - "enabled_in_config": { - "type": "boolean", - "description": "Indicates whether the connector type is enabled in the Kibana `.yml` file.", - "examples": [ - true - ] - }, - "enabled_in_license": { - "type": "boolean", - "description": "Indicates whether the connector is enabled in the license.", - "examples": [ - true - ] - }, - "id": { - "$ref": "#/components/schemas/connector_types" - }, - "minimum_license_required": { - "type": "string", - "description": "The license that is required to use the connector type.", - "examples": [ - "basic" - ] - }, - "name": { - "type": "string", - "description": "The name of the connector type.", - "examples": [ - "Index" - ] - }, - "supported_feature_ids": { - "type": "array", - "description": "The Kibana features that are supported by the connector type.", - "items": { - "$ref": "#/components/schemas/features" - }, - "examples": [ - [ - "alerting", - "uptime", - "siem" - ] - ] - } - } - } - }, - "examples": { - "getConnectorTypesResponse": { - "$ref": "#/components/examples/get_connector_types_response" - } - } - } - } - }, - "401": { - "$ref": "#/components/responses/401" - } - } - } - }, - "/s/{spaceId}/api/actions/connector/{connectorId}/_execute": { + "/api/actions/connector/{connectorId}/_execute": { "post": { - "summary": "Runs a connector.", - "operationId": "runConnectorWithSpaceId", + "summary": "Run a connector", + "operationId": "runConnector", "description": "You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. If you use an index connector, you must also have `all`, `create`, `index`, or `write` indices privileges.\n", "tags": [ "connectors" @@ -957,9 +796,6 @@ }, { "$ref": "#/components/parameters/connector_id" - }, - { - "$ref": "#/components/parameters/space_id" } ], "requestBody": { @@ -970,12 +806,21 @@ "$ref": "#/components/schemas/run_connector_request" }, "examples": { + "runCasesWebhookConnectorRequest": { + "$ref": "#/components/examples/run_cases_webhook_connector_request" + }, + "runEmailConnectorRequest": { + "$ref": "#/components/examples/run_email_connector_request" + }, "runIndexConnectorRequest": { "$ref": "#/components/examples/run_index_connector_request" }, "runJiraConnectorRequest": { "$ref": "#/components/examples/run_jira_connector_request" }, + "runPagerDutyConnectorRequest": { + "$ref": "#/components/examples/run_pagerduty_connector_request" + }, "runServerLogConnectorRequest": { "$ref": "#/components/examples/run_server_log_connector_request" }, @@ -1024,12 +869,6 @@ } ] }, - "message": { - "type": "string" - }, - "service_message": { - "type": "string" - }, "status": { "type": "string", "description": "The status of the action.", @@ -1041,12 +880,21 @@ } }, "examples": { + "runCasesWebhookConnectorResponse": { + "$ref": "#/components/examples/run_cases_webhook_connector_response" + }, + "runEmailConnectorResponse": { + "$ref": "#/components/examples/run_email_connector_response" + }, "runIndexConnectorResponse": { "$ref": "#/components/examples/run_index_connector_response" }, "runJiraConnectorResponse": { "$ref": "#/components/examples/run_jira_connector_response" }, + "runPagerDutyConnectorResponse": { + "$ref": "#/components/examples/run_pagerduty_connector_response" + }, "runServerLogConnectorResponse": { "$ref": "#/components/examples/run_server_log_connector_response" }, @@ -1069,9 +917,131 @@ } } }, + "/api/actions/connectors": { + "get": { + "summary": "Get all connectors", + "operationId": "getConnectors", + "tags": [ + "connectors" + ], + "responses": { + "200": { + "description": "Indicates a successful call.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/connector_response_properties" + } + }, + "examples": { + "getConnectorsResponse": { + "$ref": "#/components/examples/get_connectors_response" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/api/actions/connector_types": { + "get": { + "summary": "Get all connector types", + "operationId": "getConnectorTypes", + "tags": [ + "connectors" + ], + "parameters": [ + { + "in": "query", + "name": "feature_id", + "description": "A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases).", + "schema": { + "$ref": "#/components/schemas/features" + } + } + ], + "responses": { + "200": { + "description": "Indicates a successful call.", + "content": { + "application/json": { + "schema": { + "title": "Get connector types response body properties", + "description": "The properties vary for each connector type.", + "type": "array", + "items": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Indicates whether the connector type is enabled in Kibana.", + "example": true + }, + "enabled_in_config": { + "type": "boolean", + "description": "Indicates whether the connector type is enabled in the Kibana configuration file.", + "example": true + }, + "enabled_in_license": { + "type": "boolean", + "description": "Indicates whether the connector is enabled in the license.", + "example": true + }, + "id": { + "$ref": "#/components/schemas/connector_types" + }, + "is_system_action_type": { + "type": "boolean", + "example": false + }, + "minimum_license_required": { + "type": "string", + "description": "The license that is required to use the connector type.", + "example": "basic" + }, + "name": { + "type": "string", + "description": "The name of the connector type.", + "example": "Index" + }, + "supported_feature_ids": { + "type": "array", + "description": "The features that are supported by the connector type.", + "items": { + "$ref": "#/components/schemas/features" + }, + "example": [ + "alerting", + "cases", + "siem" + ] + } + } + } + }, + "examples": { + "getConnectorTypesServerlessResponse": { + "$ref": "#/components/examples/get_connector_types_generativeai_response" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, "/s/{spaceId}/api/actions/action/{actionId}": { "delete": { - "summary": "Deletes a connector.", + "summary": "Delete a connector", "operationId": "legacyDeleteConnector", "deprecated": true, "description": "Deprecated in 7.13.0. Use the delete connector API instead. WARNING: When you delete a connector, it cannot be recovered.\n", @@ -1099,7 +1069,7 @@ } }, "get": { - "summary": "Retrieves a connector by ID.", + "summary": "Get connector information", "operationId": "legacyGetConnector", "description": "Deprecated in 7.13.0. Use the get connector API instead.", "deprecated": true, @@ -1124,7 +1094,7 @@ } }, "put": { - "summary": "Updates the attributes for a connector.", + "summary": "Update a connector", "operationId": "legacyUpdateConnector", "deprecated": true, "description": "Deprecated in 7.13.0. Use the update connector API instead.", @@ -1180,7 +1150,7 @@ }, "/s/{spaceId}/api/actions": { "get": { - "summary": "Retrieves all connectors.", + "summary": "Get all connectors", "operationId": "legacyGetConnectors", "deprecated": true, "description": "Deprecated in 7.13.0. Use the get all connectors API instead.", @@ -1212,7 +1182,7 @@ } }, "post": { - "summary": "Creates a connector.", + "summary": "Create a connector", "operationId": "legacyCreateConnector", "deprecated": true, "description": "Deprecated in 7.13.0. Use the create connector API instead.", @@ -1268,7 +1238,7 @@ }, "/s/{spaceId}/api/actions/list_action_types": { "get": { - "summary": "Retrieves a list of all connector types.", + "summary": "Get connector types", "operationId": "legacyGetConnectorTypes", "deprecated": true, "description": "Deprecated in 7.13.0. Use the get all connector types API instead.", @@ -1303,9 +1273,7 @@ "enabledInLicense": { "type": "boolean", "description": "Indicates whether the connector is enabled in the license.", - "examples": [ - true - ] + "example": true }, "id": { "type": "string", @@ -1333,7 +1301,7 @@ }, "/s/{spaceId}/api/actions/action/{actionId}/_execute": { "post": { - "summary": "Runs a connector.", + "summary": "Run a connector", "operationId": "legacyRunConnector", "deprecated": true, "description": "Deprecated in 7.13.0. Use the run connector API instead.", @@ -1438,28 +1406,24 @@ "description": "Cross-site request forgery protection", "required": true }, - "connector_id": { + "space_id": { "in": "path", - "name": "connectorId", - "description": "An identifier for the connector.", + "name": "spaceId", + "description": "An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used.", "required": true, "schema": { "type": "string", - "examples": [ - "df770e30-8b8b-11ed-a780-3b746c987a81" - ] + "example": "default" } }, - "space_id": { + "connector_id": { "in": "path", - "name": "spaceId", - "description": "An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used.", + "name": "connectorId", + "description": "An identifier for the connector.", "required": true, "schema": { "type": "string", - "examples": [ - "default" - ] + "example": "df770e30-8b8b-11ed-a780-3b746c987a81" } }, "action_id": { @@ -1469,9 +1433,7 @@ "required": true, "schema": { "type": "string", - "examples": [ - "c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad" - ] + "example": "c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad" } } }, @@ -1496,16 +1458,12 @@ "enum": [ ".bedrock" ], - "examples": [ - ".bedrock" - ] + "example": ".bedrock" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_bedrock" @@ -1532,16 +1490,12 @@ "enum": [ ".gemini" ], - "examples": [ - ".gemini" - ] + "example": ".gemini" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_gemini" @@ -1567,16 +1521,12 @@ "enum": [ ".cases-webhook" ], - "examples": [ - ".cases-webhook" - ] + "example": ".cases-webhook" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_cases_webhook" @@ -1603,16 +1553,12 @@ "enum": [ ".d3security" ], - "examples": [ - ".d3security" - ] + "example": ".d3security" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_d3security" @@ -1639,16 +1585,12 @@ "enum": [ ".email" ], - "examples": [ - ".email" - ] + "example": ".email" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_email" @@ -1675,16 +1617,12 @@ "enum": [ ".gen-ai" ], - "examples": [ - ".gen-ai" - ] + "example": ".gen-ai" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_genai" @@ -1710,16 +1648,12 @@ "enum": [ ".index" ], - "examples": [ - ".index" - ] + "example": ".index" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" } } }, @@ -1743,16 +1677,12 @@ "enum": [ ".jira" ], - "examples": [ - ".jira" - ] + "example": ".jira" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_jira" @@ -1779,16 +1709,12 @@ "enum": [ ".opsgenie" ], - "examples": [ - ".opsgenie" - ] + "example": ".opsgenie" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_opsgenie" @@ -1815,16 +1741,12 @@ "enum": [ ".pagerduty" ], - "examples": [ - ".pagerduty" - ] + "example": ".pagerduty" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_pagerduty" @@ -1848,9 +1770,7 @@ "connector_type_id": { "description": "The type of connector.", "type": "string", - "examples": [ - ".resilient" - ], + "example": ".resilient", "enum": [ ".resilient" ] @@ -1858,9 +1778,7 @@ "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_resilient" @@ -1888,16 +1806,12 @@ "enum": [ ".sentinelone" ], - "examples": [ - ".sentinelone" - ] + "example": ".sentinelone" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_sentinelone" @@ -1919,16 +1833,12 @@ "enum": [ ".server-log" ], - "examples": [ - ".server-log" - ] + "example": ".server-log" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" } } }, @@ -1952,16 +1862,12 @@ "enum": [ ".servicenow" ], - "examples": [ - ".servicenow" - ] + "example": ".servicenow" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -1988,16 +1894,12 @@ "enum": [ ".servicenow-itom" ], - "examples": [ - ".servicenow-itom" - ] + "example": ".servicenow-itom" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -2024,16 +1926,12 @@ "enum": [ ".servicenow-sir" ], - "examples": [ - ".servicenow-sir" - ] + "example": ".servicenow-sir" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -2059,16 +1957,12 @@ "enum": [ ".slack_api" ], - "examples": [ - ".slack_api" - ] + "example": ".slack_api" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_slack_api" @@ -2091,16 +1985,12 @@ "enum": [ ".slack" ], - "examples": [ - ".slack" - ] + "example": ".slack" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_slack_webhook" @@ -2127,16 +2017,12 @@ "enum": [ ".swimlane" ], - "examples": [ - ".swimlane" - ] + "example": ".swimlane" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_swimlane" @@ -2159,16 +2045,12 @@ "enum": [ ".teams" ], - "examples": [ - ".teams" - ] + "example": ".teams" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_teams" @@ -2195,16 +2077,12 @@ "enum": [ ".tines" ], - "examples": [ - ".tines" - ] + "example": ".tines" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_tines" @@ -2231,16 +2109,12 @@ "enum": [ ".torq" ], - "examples": [ - ".torq" - ] + "example": ".torq" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_torq" @@ -2267,16 +2141,12 @@ "enum": [ ".webhook" ], - "examples": [ - ".webhook" - ] + "example": ".webhook" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_webhook" @@ -2303,16 +2173,12 @@ "enum": [ ".xmatters" ], - "examples": [ - ".xmatters" - ] + "example": ".xmatters" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_xmatters" @@ -2418,9 +2284,7 @@ "createCommentJson": { "type": "string", "description": "A JSON payload sent to the create comment URL to create a case comment. You can use variables to add Kibana Cases data to the payload. The required variable is `case.comment`. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass.\n", - "examples": [ - "{\"body\": {{{case.comment}}}}" - ] + "example": "{\"body\": {{{case.comment}}}}" }, "createCommentMethod": { "type": "string", @@ -2435,16 +2299,12 @@ "createCommentUrl": { "type": "string", "description": "The REST API URL to create a case comment by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts.\n", - "examples": [ - "https://example.com/issue/{{{external.system.id}}}/comment" - ] + "example": "https://example.com/issue/{{{external.system.id}}}/comment" }, "createIncidentJson": { "type": "string", "description": "A JSON payload sent to the create case URL to create a case. You can use variables to add case data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review.\n", - "examples": [ - "{\"fields\": {\"summary\": {{{case.title}}},\"description\": {{{case.description}}},\"labels\": {{{case.tags}}}}}" - ] + "example": "{\"fields\": {\"summary\": {{{case.title}}},\"description\": {{{case.description}}},\"labels\": {{{case.tags}}}}}" }, "createIncidentMethod": { "type": "string", @@ -2471,9 +2331,7 @@ "getIncidentUrl": { "type": "string", "description": "The REST API URL to get the case by ID from the third-party system. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. You can use a variable to add the external system ID to the URL. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass.\n", - "examples": [ - "https://example.com/issue/{{{external.system.id}}}" - ] + "example": "https://example.com/issue/{{{external.system.id}}}" }, "hasAuth": { "type": "boolean", @@ -2487,9 +2345,7 @@ "updateIncidentJson": { "type": "string", "description": "The JSON payload sent to the update case URL to update the case. You can use variables to add Kibana Cases data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review.\n", - "examples": [ - "{\"fields\": {\"summary\": {{{case.title}}},\"description\": {{{case.description}}},\"labels\": {{{case.tags}}}}}" - ] + "example": "{\"fields\": {\"summary\": {{{case.title}}},\"description\": {{{case.description}}},\"labels\": {{{case.tags}}}}}" }, "updateIncidentMethod": { "type": "string", @@ -2504,16 +2360,12 @@ "updateIncidentUrl": { "type": "string", "description": "The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts.\n", - "examples": [ - "https://example.com/issue/{{{external.system.ID}}}" - ] + "example": "https://example.com/issue/{{{external.system.ID}}}" }, "viewIncidentUrl": { "type": "string", "description": "The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL.\n", - "examples": [ - "https://testing-jira.atlassian.net/browse/{{{external.system.title}}}" - ] + "example": "https://testing-jira.atlassian.net/browse/{{{external.system.title}}}" } } }, @@ -2569,10 +2421,8 @@ "properties": { "clientId": { "description": "The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true }, "from": { "description": "The from address for all emails sent by the connector. It must be specified in `user@host-name` format.\n", @@ -2588,10 +2438,8 @@ "type": "string" }, "oauthTokenUrl": { - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true }, "port": { "description": "The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. \n", @@ -2615,10 +2463,8 @@ }, "tenantId": { "description": "The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true } } }, @@ -2730,10 +2576,8 @@ "executionTimeField": { "description": "A field that indicates when the document was indexed.", "default": null, - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true }, "index": { "description": "The Elasticsearch index to be written to.", @@ -2819,13 +2663,9 @@ "properties": { "apiUrl": { "description": "The PagerDuty event URL.", - "type": [ - "string", - "null" - ], - "examples": [ - "https://events.pagerduty.com/v2/enqueue" - ] + "type": "string", + "nullable": true, + "example": "https://events.pagerduty.com/v2/enqueue" } } }, @@ -3395,10 +3235,10 @@ "properties": { "authType": { "type": "string", + "nullable": true, "enum": [ "webhook-authentication-basic", - "webhook-authentication-ssl", - "null" + "webhook-authentication-ssl" ], "description": "The type of authentication to use: basic, SSL, or none.\n" }, @@ -3419,10 +3259,8 @@ "description": "If `true`, a user name and password must be provided for login type authentication.\n" }, "headers": { - "type": [ - "object", - "null" - ], + "type": "object", + "nullable": true, "description": "A set of key-value pairs sent as headers with the request." }, "method": { @@ -3484,10 +3322,8 @@ "properties": { "configUrl": { "description": "The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`.\n", - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true }, "usesBasic": { "description": "Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`).", @@ -4184,10 +4020,8 @@ ], "properties": { "config": { - "type": [ - "object", - "null" - ] + "type": "object", + "nullable": true }, "connector_type_id": { "type": "string", @@ -4727,37 +4561,27 @@ "is_deprecated": { "type": "boolean", "description": "Indicates whether the connector type is deprecated.", - "examples": [ - false - ] + "example": false }, "is_missing_secrets": { "type": "boolean", "description": "Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type.", - "examples": [ - false - ] + "example": false }, "is_preconfigured": { "type": "boolean", "description": "Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. \n", - "examples": [ - false - ] + "example": false }, "is_system_action": { "type": "boolean", "description": "Indicates whether the connector is used for system actions.", - "examples": [ - false - ] + "example": false }, "referenced_by_count": { "type": "integer", "description": "Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API.\n", - "examples": [ - 2 - ] + "example": 2 }, "connector_response_properties": { "title": "Connector response properties", @@ -4920,9 +4744,7 @@ "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_cases_webhook" @@ -5199,9 +5021,7 @@ "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_swimlane" @@ -5384,6 +5204,51 @@ } ] }, + "features": { + "type": "string", + "description": "The feature that uses the connector.\n", + "enum": [ + "alerting", + "cases", + "generativeAIForSecurity", + "generativeAIForObservability", + "generativeAIForSearchPlayground", + "siem", + "uptime" + ] + }, + "connector_types": { + "title": "Connector types", + "type": "string", + "description": "The type of connector. For example, `.email`, `.index`, `.jira`, `.opsgenie`, or `.server-log`.", + "enum": [ + ".bedrock", + ".gemini", + ".cases-webhook", + ".d3security", + ".email", + ".gen-ai", + ".index", + ".jira", + ".opsgenie", + ".pagerduty", + ".resilient", + ".sentinelone", + ".servicenow", + ".servicenow-itom", + ".servicenow-sir", + ".server-log", + ".slack", + ".slack_api", + ".swimlane", + ".teams", + ".tines", + ".torq", + ".webhook", + ".xmatters" + ], + "example": ".server-log" + }, "run_connector_params_acknowledge_resolve_pagerduty": { "title": "PagerDuty connector parameters", "description": "Test an action that acknowledges or resolves a PagerDuty alert.", @@ -5537,16 +5402,12 @@ "class": { "description": "The class or type of the event.", "type": "string", - "examples": [ - "cpu load" - ] + "example": "cpu load" }, "component": { "description": "The component of the source machine that is responsible for the event.", "type": "string", - "examples": [ - "eth0" - ] + "example": "eth0" }, "customDetails": { "description": "Additional details to add to the event.", @@ -5567,9 +5428,7 @@ "group": { "description": "The logical grouping of components of a service.", "type": "string", - "examples": [ - "app-stack" - ] + "example": "app-stack" }, "links": { "description": "A list of links to add to the event.", @@ -5762,19 +5621,15 @@ ], "properties": { "correlation_id": { - "type": [ - "null", - "string" - ], + "type": "string", + "nullable": true, "description": "An identifier that is assigned to the incident when it is created by the connector. NOTE: If you use the default value and the rule generates multiple alerts that use the same alert IDs, the latest open incident for this correlation ID is closed unless you specify the external ID.\n", "maxLength": 100, "default": "{{rule.id}}:{{alert.id}}" }, "externalId": { - "type": [ - "null", - "string" - ], + "type": "string", + "nullable": true, "description": "The unique identifier (`incidentId`) for the incident in ServiceNow." } } @@ -5824,12 +5679,10 @@ "type": "object", "description": "The custom properties of the alert.", "additionalProperties": true, - "examples": [ - { - "key1": "value1", - "key2": "value2" - } - ] + "example": { + "key1": "value1", + "key2": "value2" + } }, "entity": { "type": "string", @@ -5961,9 +5814,7 @@ "id": { "type": "string", "description": "The Jira issue type identifier.", - "examples": [ - 10024 - ] + "example": 10024 } } } @@ -6045,9 +5896,7 @@ "externalId": { "type": "string", "description": "The Jira, ServiceNow ITSM, or ServiceNow SecOps issue identifier.", - "examples": [ - 71778 - ] + "example": 71778 } } } @@ -6077,9 +5926,7 @@ "id": { "type": "string", "description": "The Jira issue identifier.", - "examples": [ - 71778 - ] + "example": 71778 } } } @@ -6514,53 +6361,6 @@ } } }, - "features": { - "type": "string", - "description": "The feature that uses the connector.\n", - "enum": [ - "alerting", - "cases", - "generativeAIForSecurity", - "generativeAIForObservability", - "generativeAIForSearchPlayground", - "siem", - "uptime" - ] - }, - "connector_types": { - "title": "Connector types", - "type": "string", - "description": "The type of connector. For example, `.email`, `.index`, `.jira`, `.opsgenie`, or `.server-log`.", - "enum": [ - ".bedrock", - ".gemini", - ".cases-webhook", - ".d3security", - ".email", - ".gen-ai", - ".index", - ".jira", - ".opsgenie", - ".pagerduty", - ".resilient", - ".sentinelone", - ".servicenow", - ".servicenow-itom", - ".servicenow-sir", - ".server-log", - ".slack", - ".slack_api", - ".swimlane", - ".teams", - ".tines", - ".torq", - ".webhook", - ".xmatters" - ], - "examples": [ - ".server-log" - ] - }, "action_response_properties": { "title": "Action response properties", "description": "The properties vary depending on the action type.", @@ -6753,51 +6553,77 @@ } } }, - "run_cases_webhook_connector_request": { - "summary": "Run a Webhook - Case Management connector to create a case.", - "value": { - "params": { - "subAction": "pushToService", - "subActionParams": { - "comments": [ - { - "commentId": 1, - "comment": "A comment about the incident." - } - ], - "incident": { - "title": "Case title", - "description": "Description of the incident.", - "tags": [ - "tag1", - "tag2" - ], - "severity": "low", - "status": "open", - "id": "caseID" - } - } + "get_connectors_response": { + "summary": "A list of connectors", + "value": [ + { + "id": "preconfigured-email-connector", + "name": "my-preconfigured-email-notification", + "connector_type_id": ".email", + "is_preconfigured": true, + "is_deprecated": false, + "referenced_by_count": 0, + "is_system_action": false + }, + { + "id": "e07d0c80-8b8b-11ed-a780-3b746c987a81", + "name": "my-index-connector", + "config": { + "index": "test-index", + "refresh": false, + "executionTimeField": null + }, + "connector_type_id": ".index", + "is_preconfigured": false, + "is_deprecated": false, + "referenced_by_count": 2, + "is_missing_secrets": false, + "is_system_action": false } - } + ] }, - "run_email_connector_request": { - "summary": "Send an email message from an email connector.", - "value": { - "params": { - "bcc": [ - "user1@example.com" - ], - "cc": [ - "user2@example.com", - "user3@example.com" - ], - "message": "Test email message.", - "subject": "Test message subject", - "to": [ - "user4@example.com" + "get_connector_types_response": { + "summary": "A list of connector types", + "value": [ + { + "id": ".swimlane", + "name": "Swimlane", + "enabled": true, + "enabled_in_config": true, + "enabled_in_license": true, + "minimum_license_required": "gold", + "supported_feature_ids": [ + "alerting", + "cases", + "siem" + ] + }, + { + "id": ".index", + "name": "Index", + "enabled": true, + "enabled_in_config": true, + "enabled_in_license": true, + "minimum_license_required": "basic", + "supported_feature_ids": [ + "alerting", + "uptime", + "siem" + ] + }, + { + "id": ".server-log", + "name": "Server log", + "enabled": true, + "enabled_in_config": true, + "enabled_in_license": true, + "minimum_license_required": "basic", + "supported_feature_ids": [ + "alerting", + "uptime" ] } - } + ] }, "run_index_connector_request": { "summary": "Run an index connector.", @@ -6821,24 +6647,6 @@ } } }, - "run_pagerduty_connector_request": { - "summary": "Run a PagerDuty connector to trigger an alert.", - "value": { - "params": { - "eventAction": "trigger", - "summary": "A brief event summary", - "links": [ - { - "href": "http://example.com/pagerduty", - "text": "An example link" - } - ], - "customDetails": { - "my_data_1": "test data" - } - } - } - }, "run_server_log_connector_request": { "summary": "Run a server log connector.", "value": { @@ -6875,75 +6683,26 @@ } } } - }, - "run_swimlane_connector_request": { - "summary": "Run a Swimlane connector to create an incident.", - "value": { - "params": { - "subAction": "pushToService", - "subActionParams": { - "comments": [ - { - "commentId": 1, - "comment": "A comment about the incident." - } - ], - "incident": { - "caseId": "1000", - "caseName": "Case name", - "description": "Description of the incident." - } - } - } - } - }, - "run_cases_webhook_connector_response": { - "summary": "Response from a pushToService action for a Webhook - Case Management connector.", - "value": { - "connector_id": "1824b5b8-c005-4dcc-adac-57f92db46459", - "data": { - "id": 100665, - "title": "TEST-29034", - "url": "https://example.com/browse/TEST-29034", - "pushedDate": "2023-12-05T19:43:36.360Z", - "comments": [ - { - "commentId": 1, - "pushedDate": "2023-12-05T19:43:36.360Z" - } - ] - }, - "status": "ok" - } - }, - "run_email_connector_response": { - "summary": "Response for sending a message from an email connector.", + }, + "run_swimlane_connector_request": { + "summary": "Run a Swimlane connector to create an incident.", "value": { - "connector_id": "7fc7b9a0-ecc9-11ec-8736-e7d63118c907", - "data": { - "accepted": [ - "user1@example.com", - "user2@example.com", - "user3@example.com", - "user4@example.com" - ], - "envelope": { - "from": "tester@example.com", - "to": [ - "user1@example.com", - "user2@example.com", - "user3@example.com", - "user4@example.com" - ] - }, - "envelopeTime": 8, - "messageTime": 3, - "messageSize": 729, - "response": "250 Message queued as QzEXKcGJ", - "messageId": "<08a92d29-642a-0706-750c-de5996bd5cf3@example.com>", - "rejected": [] - }, - "status": "ok" + "params": { + "subAction": "pushToService", + "subActionParams": { + "comments": [ + { + "commentId": 1, + "comment": "A comment about the incident." + } + ], + "incident": { + "caseId": "1000", + "caseName": "Case name", + "description": "Description of the incident." + } + } + } } }, "run_index_connector_response": { @@ -7008,18 +6767,6 @@ "status": "ok" } }, - "run_pagerduty_connector_response": { - "summary": "Response from running a PagerDuty connector.", - "value": { - "connector_id": "45de9f70-954f-4608-b12a-db7cf808e49d", - "data": { - "dedup_key": "5115e138b26b484a81eaea779faa6016", - "message": "Event processed", - "status": "success" - }, - "status": "ok" - } - }, "run_server_log_connector_response": { "summary": "Response from running a server log connector.", "value": { @@ -7158,34 +6905,130 @@ "status": "ok" } }, - "get_connectors_response": { - "summary": "A list of connectors", - "value": [ - { - "id": "preconfigured-email-connector", - "name": "my-preconfigured-email-notification", - "connector_type_id": ".email", - "is_preconfigured": true, - "is_deprecated": false, - "referenced_by_count": 0, - "is_system_action": false + "run_cases_webhook_connector_request": { + "summary": "Run a Webhook - Case Management connector to create a case.", + "value": { + "params": { + "subAction": "pushToService", + "subActionParams": { + "comments": [ + { + "commentId": 1, + "comment": "A comment about the incident." + } + ], + "incident": { + "title": "Case title", + "description": "Description of the incident.", + "tags": [ + "tag1", + "tag2" + ], + "severity": "low", + "status": "open", + "id": "caseID" + } + } + } + } + }, + "run_email_connector_request": { + "summary": "Send an email message from an email connector.", + "value": { + "params": { + "bcc": [ + "user1@example.com" + ], + "cc": [ + "user2@example.com", + "user3@example.com" + ], + "message": "Test email message.", + "subject": "Test message subject", + "to": [ + "user4@example.com" + ] + } + } + }, + "run_pagerduty_connector_request": { + "summary": "Run a PagerDuty connector to trigger an alert.", + "value": { + "params": { + "eventAction": "trigger", + "summary": "A brief event summary", + "links": [ + { + "href": "http://example.com/pagerduty", + "text": "An example link" + } + ], + "customDetails": { + "my_data_1": "test data" + } + } + } + }, + "run_cases_webhook_connector_response": { + "summary": "Response from a pushToService action for a Webhook - Case Management connector.", + "value": { + "connector_id": "1824b5b8-c005-4dcc-adac-57f92db46459", + "data": { + "id": 100665, + "title": "TEST-29034", + "url": "https://example.com/browse/TEST-29034", + "pushedDate": "2023-12-05T19:43:36.360Z", + "comments": [ + { + "commentId": 1, + "pushedDate": "2023-12-05T19:43:36.360Z" + } + ] }, - { - "id": "e07d0c80-8b8b-11ed-a780-3b746c987a81", - "name": "my-index-connector", - "config": { - "index": "test-index", - "refresh": false, - "executionTimeField": null + "status": "ok" + } + }, + "run_email_connector_response": { + "summary": "Response for sending a message from an email connector.", + "value": { + "connector_id": "7fc7b9a0-ecc9-11ec-8736-e7d63118c907", + "data": { + "accepted": [ + "user1@example.com", + "user2@example.com", + "user3@example.com", + "user4@example.com" + ], + "envelope": { + "from": "tester@example.com", + "to": [ + "user1@example.com", + "user2@example.com", + "user3@example.com", + "user4@example.com" + ] }, - "connector_type_id": ".index", - "is_preconfigured": false, - "is_deprecated": false, - "referenced_by_count": 2, - "is_missing_secrets": false, - "is_system_action": false - } - ] + "envelopeTime": 8, + "messageTime": 3, + "messageSize": 729, + "response": "250 Message queued as QzEXKcGJ", + "messageId": "<08a92d29-642a-0706-750c-de5996bd5cf3@example.com>", + "rejected": [] + }, + "status": "ok" + } + }, + "run_pagerduty_connector_response": { + "summary": "Response from running a PagerDuty connector.", + "value": { + "connector_id": "45de9f70-954f-4608-b12a-db7cf808e49d", + "data": { + "dedup_key": "5115e138b26b484a81eaea779faa6016", + "message": "Event processed", + "status": "success" + }, + "status": "ok" + } }, "get_connector_types_generativeai_response": { "summary": "A list of connector types for the `generativeAI` feature.", @@ -7231,49 +7074,6 @@ "is_system_action_type": false } ] - }, - "get_connector_types_response": { - "summary": "A list of connector types", - "value": [ - { - "id": ".swimlane", - "name": "Swimlane", - "enabled": true, - "enabled_in_config": true, - "enabled_in_license": true, - "minimum_license_required": "gold", - "supported_feature_ids": [ - "alerting", - "cases", - "siem" - ] - }, - { - "id": ".index", - "name": "Index", - "enabled": true, - "enabled_in_config": true, - "enabled_in_license": true, - "minimum_license_required": "basic", - "supported_feature_ids": [ - "alerting", - "uptime", - "siem" - ] - }, - { - "id": ".server-log", - "name": "Server log", - "enabled": true, - "enabled_in_config": true, - "enabled_in_license": true, - "minimum_license_required": "basic", - "supported_feature_ids": [ - "alerting", - "uptime" - ] - } - ] } }, "responses": { @@ -7287,9 +7087,7 @@ "properties": { "error": { "type": "string", - "examples": [ - "Unauthorized" - ], + "example": "Unauthorized", "enum": [ "Unauthorized" ] @@ -7299,9 +7097,7 @@ }, "statusCode": { "type": "integer", - "examples": [ - 401 - ], + "example": 401, "enum": [ 401 ] @@ -7321,24 +7117,18 @@ "properties": { "error": { "type": "string", - "examples": [ - "Not Found" - ], + "example": "Not Found", "enum": [ "Not Found" ] }, "message": { "type": "string", - "examples": [ - "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" - ] + "example": "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" }, "statusCode": { "type": "integer", - "examples": [ - 404 - ], + "example": 404, "enum": [ 404 ] diff --git a/x-pack/plugins/actions/docs/openapi/bundled.yaml b/x-pack/plugins/actions/docs/openapi/bundled.yaml index c9628f9916c6fe..95a0449bec1928 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.yaml +++ b/x-pack/plugins/actions/docs/openapi/bundled.yaml @@ -1,4 +1,4 @@ -openapi: 3.1.0 +openapi: 3.0.3 info: title: Connectors description: OpenAPI schema for Connectors endpoints @@ -17,14 +17,17 @@ tags: - name: connectors description: Connector APIs enable you to create and manage connectors. paths: - /api/actions/connector: + /s/{spaceId}/api/actions/connector: post: - summary: Creates a connector. - operationId: createConnector + summary: Create a connector + operationId: createConnectorWithSpaceId + description: | + You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. tags: - connectors parameters: - $ref: '#/components/parameters/kbn_xsrf' + - $ref: '#/components/parameters/space_id' requestBody: required: true content: @@ -58,14 +61,17 @@ paths: $ref: '#/components/examples/create_xmatters_connector_response' '401': $ref: '#/components/responses/401' - /api/actions/connector/{connectorId}: + /s/{spaceId}/api/actions/connector/{connectorId}: get: - summary: Retrieves a connector by ID. - operationId: getConnector + summary: Get connector information + operationId: getConnectorWithSpaceId + description: | + You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. tags: - connectors parameters: - $ref: '#/components/parameters/connector_id' + - $ref: '#/components/parameters/space_id' responses: '200': description: Indicates a successful call. @@ -81,13 +87,16 @@ paths: '404': $ref: '#/components/responses/404' delete: - summary: Deletes a connector. - operationId: deleteConnector + summary: Delete a connector + operationId: deleteConnectorWithSpaceId + description: | + You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. WARNING: When you delete a connector, it cannot be recovered. tags: - connectors parameters: - $ref: '#/components/parameters/kbn_xsrf' - $ref: '#/components/parameters/connector_id' + - $ref: '#/components/parameters/space_id' responses: '204': description: Indicates a successful call. @@ -96,21 +105,22 @@ paths: '404': $ref: '#/components/responses/404' post: - summary: Creates a connector. - operationId: createConnectorId + summary: Create a connector + operationId: createConnectorIdWithSpaceId + description: | + You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. tags: - connectors parameters: - $ref: '#/components/parameters/kbn_xsrf' + - $ref: '#/components/parameters/space_id' - in: path name: connectorId - description: | - A UUID v1 or v4 identifier for the connector. If you omit this parameter, an identifier is randomly generated. + description: A UUID v1 or v4 identifier for the connector. If you omit this parameter, an identifier is randomly generated. required: true schema: type: string - examples: - - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: @@ -133,13 +143,16 @@ paths: '401': $ref: '#/components/responses/401' put: - summary: Updates the attributes for a connector. - operationId: updateConnector + summary: Update a connector + operationId: updateConnectorWithSpaceId + description: | + You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. tags: - connectors parameters: - $ref: '#/components/parameters/kbn_xsrf' - $ref: '#/components/parameters/connector_id' + - $ref: '#/components/parameters/space_id' requestBody: required: true content: @@ -162,10 +175,97 @@ paths: $ref: '#/components/responses/401' '404': $ref: '#/components/responses/404' - /api/actions/connector/{connectorId}/_execute: + /s/{spaceId}/api/actions/connectors: + get: + summary: Get all connectors + operationId: getConnectorsWithSpaceId + description: | + You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/connector_response_properties' + examples: + getConnectorsResponse: + $ref: '#/components/examples/get_connectors_response' + '401': + $ref: '#/components/responses/401' + /s/{spaceId}/api/actions/connector_types: + get: + summary: Get all connector types + operationId: getConnectorTypesWithSpaceId + description: | + You do not need any Kibana feature privileges to run this API. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/space_id' + - in: query + name: feature_id + description: A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases). + schema: + $ref: '#/components/schemas/features' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + title: Get connector types response body properties + description: The properties vary for each connector type. + type: array + items: + type: object + properties: + enabled: + type: boolean + description: Indicates whether the connector type is enabled in Kibana. + example: true + enabled_in_config: + type: boolean + description: Indicates whether the connector type is enabled in the Kibana `.yml` file. + example: true + enabled_in_license: + type: boolean + description: Indicates whether the connector is enabled in the license. + example: true + id: + $ref: '#/components/schemas/connector_types' + minimum_license_required: + type: string + description: The license that is required to use the connector type. + example: basic + name: + type: string + description: The name of the connector type. + example: Index + supported_feature_ids: + type: array + description: The Kibana features that are supported by the connector type. + items: + $ref: '#/components/schemas/features' + example: + - alerting + - uptime + - siem + examples: + getConnectorTypesResponse: + $ref: '#/components/examples/get_connector_types_response' + '401': + $ref: '#/components/responses/401' + /s/{spaceId}/api/actions/connector/{connectorId}/_execute: post: - summary: Runs a connector. - operationId: runConnector + summary: Run a connector + operationId: runConnectorWithSpaceId description: | You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. If you use an index connector, you must also have `all`, `create`, `index`, or `write` indices privileges. tags: @@ -173,6 +273,7 @@ paths: parameters: - $ref: '#/components/parameters/kbn_xsrf' - $ref: '#/components/parameters/connector_id' + - $ref: '#/components/parameters/space_id' requestBody: required: true content: @@ -180,16 +281,10 @@ paths: schema: $ref: '#/components/schemas/run_connector_request' examples: - runCasesWebhookConnectorRequest: - $ref: '#/components/examples/run_cases_webhook_connector_request' - runEmailConnectorRequest: - $ref: '#/components/examples/run_email_connector_request' runIndexConnectorRequest: $ref: '#/components/examples/run_index_connector_request' runJiraConnectorRequest: $ref: '#/components/examples/run_jira_connector_request' - runPagerDutyConnectorRequest: - $ref: '#/components/examples/run_pagerduty_connector_request' runServerLogConnectorRequest: $ref: '#/components/examples/run_server_log_connector_request' runServiceNowITOMConnectorRequest: @@ -221,6 +316,10 @@ paths: description: An array of information returned from the action. items: type: object + message: + type: string + service_message: + type: string status: type: string description: The status of the action. @@ -228,16 +327,10 @@ paths: - error - ok examples: - runCasesWebhookConnectorResponse: - $ref: '#/components/examples/run_cases_webhook_connector_response' - runEmailConnectorResponse: - $ref: '#/components/examples/run_email_connector_response' runIndexConnectorResponse: $ref: '#/components/examples/run_index_connector_response' runJiraConnectorResponse: $ref: '#/components/examples/run_jira_connector_response' - runPagerDutyConnectorResponse: - $ref: '#/components/examples/run_pagerduty_connector_response' runServerLogConnectorResponse: $ref: '#/components/examples/run_server_log_connector_response' runServiceNowITOMConnectorResponse: @@ -248,106 +341,14 @@ paths: $ref: '#/components/examples/run_swimlane_connector_response' '401': $ref: '#/components/responses/401' - /api/actions/connectors: - get: - summary: Retrieves all connectors. - operationId: getConnectors - tags: - - connectors - responses: - '200': - description: Indicates a successful call. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/connector_response_properties' - examples: - getConnectorsResponse: - $ref: '#/components/examples/get_connectors_response' - '401': - $ref: '#/components/responses/401' - /api/actions/connector_types: - get: - summary: Retrieves a list of all connector types. - operationId: getConnectorTypes - tags: - - connectors - parameters: - - in: query - name: feature_id - description: A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases). - schema: - $ref: '#/components/schemas/features' - responses: - '200': - description: Indicates a successful call. - content: - application/json: - schema: - title: Get connector types response body properties - description: The properties vary for each connector type. - type: array - items: - type: object - properties: - enabled: - type: boolean - description: Indicates whether the connector type is enabled in Kibana. - examples: - - true - enabled_in_config: - type: boolean - description: Indicates whether the connector type is enabled in the Kibana configuration file. - examples: - - true - enabled_in_license: - type: boolean - description: Indicates whether the connector is enabled in the license. - examples: - - true - id: - $ref: '#/components/schemas/connector_types' - is_system_action_type: - type: boolean - examples: - - false - minimum_license_required: - type: string - description: The license that is required to use the connector type. - examples: - - basic - name: - type: string - description: The name of the connector type. - examples: - - Index - supported_feature_ids: - type: array - description: The features that are supported by the connector type. - items: - $ref: '#/components/schemas/features' - examples: - - - alerting - - cases - - siem - examples: - getConnectorTypesServerlessResponse: - $ref: '#/components/examples/get_connector_types_generativeai_response' - '401': - $ref: '#/components/responses/401' - /s/{spaceId}/api/actions/connector: + /api/actions/connector: post: - summary: Creates a connector. - operationId: createConnectorWithSpaceId - description: | - You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. + summary: Create a connector + operationId: createConnector tags: - connectors parameters: - $ref: '#/components/parameters/kbn_xsrf' - - $ref: '#/components/parameters/space_id' requestBody: required: true content: @@ -381,17 +382,14 @@ paths: $ref: '#/components/examples/create_xmatters_connector_response' '401': $ref: '#/components/responses/401' - /s/{spaceId}/api/actions/connector/{connectorId}: + /api/actions/connector/{connectorId}: get: - summary: Retrieves a connector by ID. - operationId: getConnectorWithSpaceId - description: | - You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. + summary: Get a connector information + operationId: getConnector tags: - connectors parameters: - $ref: '#/components/parameters/connector_id' - - $ref: '#/components/parameters/space_id' responses: '200': description: Indicates a successful call. @@ -407,16 +405,13 @@ paths: '404': $ref: '#/components/responses/404' delete: - summary: Deletes a connector. - operationId: deleteConnectorWithSpaceId - description: | - You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. WARNING: When you delete a connector, it cannot be recovered. + summary: Delete a connector + operationId: deleteConnector tags: - connectors parameters: - $ref: '#/components/parameters/kbn_xsrf' - $ref: '#/components/parameters/connector_id' - - $ref: '#/components/parameters/space_id' responses: '204': description: Indicates a successful call. @@ -425,23 +420,20 @@ paths: '404': $ref: '#/components/responses/404' post: - summary: Creates a connector. - operationId: createConnectorIdWithSpaceId - description: | - You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. + summary: Create a connector + operationId: createConnectorId tags: - connectors parameters: - $ref: '#/components/parameters/kbn_xsrf' - - $ref: '#/components/parameters/space_id' - in: path name: connectorId - description: A UUID v1 or v4 identifier for the connector. If you omit this parameter, an identifier is randomly generated. + description: | + A UUID v1 or v4 identifier for the connector. If you omit this parameter, an identifier is randomly generated. required: true schema: type: string - examples: - - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: @@ -464,16 +456,13 @@ paths: '401': $ref: '#/components/responses/401' put: - summary: Updates the attributes for a connector. - operationId: updateConnectorWithSpaceId - description: | - You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. + summary: Update a connector + operationId: updateConnector tags: - connectors parameters: - $ref: '#/components/parameters/kbn_xsrf' - $ref: '#/components/parameters/connector_id' - - $ref: '#/components/parameters/space_id' requestBody: required: true content: @@ -496,110 +485,17 @@ paths: $ref: '#/components/responses/401' '404': $ref: '#/components/responses/404' - /s/{spaceId}/api/actions/connectors: - get: - summary: Retrieves all connectors. - operationId: getConnectorsWithSpaceId + /api/actions/connector/{connectorId}/_execute: + post: + summary: Run a connector + operationId: runConnector description: | - You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. - tags: - - connectors - parameters: - - $ref: '#/components/parameters/space_id' - responses: - '200': - description: Indicates a successful call. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/connector_response_properties' - examples: - getConnectorsResponse: - $ref: '#/components/examples/get_connectors_response' - '401': - $ref: '#/components/responses/401' - /s/{spaceId}/api/actions/connector_types: - get: - summary: Retrieves a list of all connector types. - operationId: getConnectorTypesWithSpaceId - description: | - You do not need any Kibana feature privileges to run this API. - tags: - - connectors - parameters: - - $ref: '#/components/parameters/space_id' - - in: query - name: feature_id - description: A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases). - schema: - $ref: '#/components/schemas/features' - responses: - '200': - description: Indicates a successful call. - content: - application/json: - schema: - title: Get connector types response body properties - description: The properties vary for each connector type. - type: array - items: - type: object - properties: - enabled: - type: boolean - description: Indicates whether the connector type is enabled in Kibana. - examples: - - true - enabled_in_config: - type: boolean - description: Indicates whether the connector type is enabled in the Kibana `.yml` file. - examples: - - true - enabled_in_license: - type: boolean - description: Indicates whether the connector is enabled in the license. - examples: - - true - id: - $ref: '#/components/schemas/connector_types' - minimum_license_required: - type: string - description: The license that is required to use the connector type. - examples: - - basic - name: - type: string - description: The name of the connector type. - examples: - - Index - supported_feature_ids: - type: array - description: The Kibana features that are supported by the connector type. - items: - $ref: '#/components/schemas/features' - examples: - - - alerting - - uptime - - siem - examples: - getConnectorTypesResponse: - $ref: '#/components/examples/get_connector_types_response' - '401': - $ref: '#/components/responses/401' - /s/{spaceId}/api/actions/connector/{connectorId}/_execute: - post: - summary: Runs a connector. - operationId: runConnectorWithSpaceId - description: | - You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. If you use an index connector, you must also have `all`, `create`, `index`, or `write` indices privileges. + You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. If you use an index connector, you must also have `all`, `create`, `index`, or `write` indices privileges. tags: - connectors parameters: - $ref: '#/components/parameters/kbn_xsrf' - $ref: '#/components/parameters/connector_id' - - $ref: '#/components/parameters/space_id' requestBody: required: true content: @@ -607,10 +503,16 @@ paths: schema: $ref: '#/components/schemas/run_connector_request' examples: + runCasesWebhookConnectorRequest: + $ref: '#/components/examples/run_cases_webhook_connector_request' + runEmailConnectorRequest: + $ref: '#/components/examples/run_email_connector_request' runIndexConnectorRequest: $ref: '#/components/examples/run_index_connector_request' runJiraConnectorRequest: $ref: '#/components/examples/run_jira_connector_request' + runPagerDutyConnectorRequest: + $ref: '#/components/examples/run_pagerduty_connector_request' runServerLogConnectorRequest: $ref: '#/components/examples/run_server_log_connector_request' runServiceNowITOMConnectorRequest: @@ -642,10 +544,6 @@ paths: description: An array of information returned from the action. items: type: object - message: - type: string - service_message: - type: string status: type: string description: The status of the action. @@ -653,10 +551,16 @@ paths: - error - ok examples: + runCasesWebhookConnectorResponse: + $ref: '#/components/examples/run_cases_webhook_connector_response' + runEmailConnectorResponse: + $ref: '#/components/examples/run_email_connector_response' runIndexConnectorResponse: $ref: '#/components/examples/run_index_connector_response' runJiraConnectorResponse: $ref: '#/components/examples/run_jira_connector_response' + runPagerDutyConnectorResponse: + $ref: '#/components/examples/run_pagerduty_connector_response' runServerLogConnectorResponse: $ref: '#/components/examples/run_server_log_connector_response' runServiceNowITOMConnectorResponse: @@ -667,9 +571,92 @@ paths: $ref: '#/components/examples/run_swimlane_connector_response' '401': $ref: '#/components/responses/401' + /api/actions/connectors: + get: + summary: Get all connectors + operationId: getConnectors + tags: + - connectors + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/connector_response_properties' + examples: + getConnectorsResponse: + $ref: '#/components/examples/get_connectors_response' + '401': + $ref: '#/components/responses/401' + /api/actions/connector_types: + get: + summary: Get all connector types + operationId: getConnectorTypes + tags: + - connectors + parameters: + - in: query + name: feature_id + description: A filter to limit the retrieved connector types to those that support a specific feature (such as alerting or cases). + schema: + $ref: '#/components/schemas/features' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + title: Get connector types response body properties + description: The properties vary for each connector type. + type: array + items: + type: object + properties: + enabled: + type: boolean + description: Indicates whether the connector type is enabled in Kibana. + example: true + enabled_in_config: + type: boolean + description: Indicates whether the connector type is enabled in the Kibana configuration file. + example: true + enabled_in_license: + type: boolean + description: Indicates whether the connector is enabled in the license. + example: true + id: + $ref: '#/components/schemas/connector_types' + is_system_action_type: + type: boolean + example: false + minimum_license_required: + type: string + description: The license that is required to use the connector type. + example: basic + name: + type: string + description: The name of the connector type. + example: Index + supported_feature_ids: + type: array + description: The features that are supported by the connector type. + items: + $ref: '#/components/schemas/features' + example: + - alerting + - cases + - siem + examples: + getConnectorTypesServerlessResponse: + $ref: '#/components/examples/get_connector_types_generativeai_response' + '401': + $ref: '#/components/responses/401' /s/{spaceId}/api/actions/action/{actionId}: delete: - summary: Deletes a connector. + summary: Delete a connector operationId: legacyDeleteConnector deprecated: true description: | @@ -686,7 +673,7 @@ paths: '401': $ref: '#/components/responses/401' get: - summary: Retrieves a connector by ID. + summary: Get connector information operationId: legacyGetConnector description: Deprecated in 7.13.0. Use the get connector API instead. deprecated: true @@ -701,7 +688,7 @@ paths: '401': $ref: '#/components/responses/401' put: - summary: Updates the attributes for a connector. + summary: Update a connector operationId: legacyUpdateConnector deprecated: true description: Deprecated in 7.13.0. Use the update connector API instead. @@ -736,7 +723,7 @@ paths: $ref: '#/components/responses/404' /s/{spaceId}/api/actions: get: - summary: Retrieves all connectors. + summary: Get all connectors operationId: legacyGetConnectors deprecated: true description: Deprecated in 7.13.0. Use the get all connectors API instead. @@ -756,7 +743,7 @@ paths: '401': $ref: '#/components/responses/401' post: - summary: Creates a connector. + summary: Create a connector operationId: legacyCreateConnector deprecated: true description: Deprecated in 7.13.0. Use the create connector API instead. @@ -793,7 +780,7 @@ paths: $ref: '#/components/responses/401' /s/{spaceId}/api/actions/list_action_types: get: - summary: Retrieves a list of all connector types. + summary: Get connector types operationId: legacyGetConnectorTypes deprecated: true description: Deprecated in 7.13.0. Use the get all connector types API instead. @@ -822,8 +809,7 @@ paths: enabledInLicense: type: boolean description: Indicates whether the connector is enabled in the license. - examples: - - true + example: true id: type: string description: The unique identifier for the connector type. @@ -837,7 +823,7 @@ paths: $ref: '#/components/responses/401' /s/{spaceId}/api/actions/action/{actionId}/_execute: post: - summary: Runs a connector. + summary: Run a connector operationId: legacyRunConnector deprecated: true description: Deprecated in 7.13.0. Use the run connector API instead. @@ -903,24 +889,22 @@ components: name: kbn-xsrf description: Cross-site request forgery protection required: true - connector_id: + space_id: in: path - name: connectorId - description: An identifier for the connector. + name: spaceId + description: An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used. required: true schema: type: string - examples: - - df770e30-8b8b-11ed-a780-3b746c987a81 - space_id: + example: default + connector_id: in: path - name: spaceId - description: An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used. + name: connectorId + description: An identifier for the connector. required: true schema: type: string - examples: - - default + example: df770e30-8b8b-11ed-a780-3b746c987a81 action_id: in: path name: actionId @@ -928,8 +912,7 @@ components: required: true schema: type: string - examples: - - c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad + example: c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad schemas: create_connector_request_bedrock: title: Create Amazon Bedrock connector request @@ -948,13 +931,11 @@ components: description: The type of connector. enum: - .bedrock - examples: - - .bedrock + example: .bedrock name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_bedrock' create_connector_request_gemini: @@ -974,13 +955,11 @@ components: description: The type of connector. enum: - .gemini - examples: - - .gemini + example: .gemini name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_gemini' create_connector_request_cases_webhook: @@ -1000,13 +979,11 @@ components: description: The type of connector. enum: - .cases-webhook - examples: - - .cases-webhook + example: .cases-webhook name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_cases_webhook' create_connector_request_d3security: @@ -1027,13 +1004,11 @@ components: description: The type of connector. enum: - .d3security - examples: - - .d3security + example: .d3security name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_d3security' create_connector_request_email: @@ -1054,13 +1029,11 @@ components: description: The type of connector. enum: - .email - examples: - - .email + example: .email name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_email' create_connector_request_genai: @@ -1081,13 +1054,11 @@ components: description: The type of connector. enum: - .gen-ai - examples: - - .gen-ai + example: .gen-ai name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_genai' create_connector_request_index: @@ -1106,13 +1077,11 @@ components: description: The type of connector. enum: - .index - examples: - - .index + example: .index name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector create_connector_request_jira: title: Create Jira connector request description: The Jira connector uses the REST API v2 to create Jira issues. @@ -1130,13 +1099,11 @@ components: description: The type of connector. enum: - .jira - examples: - - .jira + example: .jira name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_jira' create_connector_request_opsgenie: @@ -1156,13 +1123,11 @@ components: description: The type of connector. enum: - .opsgenie - examples: - - .opsgenie + example: .opsgenie name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_opsgenie' create_connector_request_pagerduty: @@ -1183,13 +1148,11 @@ components: description: The type of connector. enum: - .pagerduty - examples: - - .pagerduty + example: .pagerduty name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_pagerduty' create_connector_request_resilient: @@ -1207,15 +1170,13 @@ components: connector_type_id: description: The type of connector. type: string - examples: - - .resilient + example: .resilient enum: - .resilient name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_resilient' create_connector_request_sentinelone: @@ -1237,13 +1198,11 @@ components: description: The type of connector. enum: - .sentinelone - examples: - - .sentinelone + example: .sentinelone name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_sentinelone' create_connector_request_serverlog: @@ -1259,13 +1218,11 @@ components: description: The type of connector. enum: - .server-log - examples: - - .server-log + example: .server-log name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector create_connector_request_servicenow: title: Create ServiceNow ITSM connector request description: | @@ -1284,13 +1241,11 @@ components: description: The type of connector. enum: - .servicenow - examples: - - .servicenow + example: .servicenow name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' create_connector_request_servicenow_itom: @@ -1311,13 +1266,11 @@ components: description: The type of connector. enum: - .servicenow-itom - examples: - - .servicenow-itom + example: .servicenow-itom name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' create_connector_request_servicenow_sir: @@ -1338,13 +1291,11 @@ components: description: The type of connector. enum: - .servicenow-sir - examples: - - .servicenow-sir + example: .servicenow-sir name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' create_connector_request_slack_api: @@ -1363,13 +1314,11 @@ components: description: The type of connector. enum: - .slack_api - examples: - - .slack_api + example: .slack_api name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack_api' create_connector_request_slack_webhook: @@ -1386,13 +1335,11 @@ components: description: The type of connector. enum: - .slack - examples: - - .slack + example: .slack name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack_webhook' create_connector_request_swimlane: @@ -1412,13 +1359,11 @@ components: description: The type of connector. enum: - .swimlane - examples: - - .swimlane + example: .swimlane name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_swimlane' create_connector_request_teams: @@ -1435,13 +1380,11 @@ components: description: The type of connector. enum: - .teams - examples: - - .teams + example: .teams name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_teams' create_connector_request_tines: @@ -1462,13 +1405,11 @@ components: description: The type of connector. enum: - .tines - examples: - - .tines + example: .tines name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_tines' create_connector_request_torq: @@ -1489,13 +1430,11 @@ components: description: The type of connector. enum: - .torq - examples: - - .torq + example: .torq name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_torq' create_connector_request_webhook: @@ -1516,13 +1455,11 @@ components: description: The type of connector. enum: - .webhook - examples: - - .webhook + example: .webhook name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_webhook' create_connector_request_xmatters: @@ -1543,13 +1480,11 @@ components: description: The type of connector. enum: - .xmatters - examples: - - .xmatters + example: .xmatters name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_xmatters' config_properties_bedrock: @@ -1631,8 +1566,7 @@ components: type: string description: | A JSON payload sent to the create comment URL to create a case comment. You can use variables to add Kibana Cases data to the payload. The required variable is `case.comment`. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - examples: - - '{"body": {{{case.comment}}}}' + example: '{"body": {{{case.comment}}}}' createCommentMethod: type: string description: | @@ -1646,14 +1580,12 @@ components: type: string description: | The REST API URL to create a case comment by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts. - examples: - - https://example.com/issue/{{{external.system.id}}}/comment + example: https://example.com/issue/{{{external.system.id}}}/comment createIncidentJson: type: string description: | A JSON payload sent to the create case URL to create a case. You can use variables to add case data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - examples: - - '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' + example: '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' createIncidentMethod: type: string description: | @@ -1677,8 +1609,7 @@ components: type: string description: | The REST API URL to get the case by ID from the third-party system. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. You can use a variable to add the external system ID to the URL. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - examples: - - https://example.com/issue/{{{external.system.id}}} + example: https://example.com/issue/{{{external.system.id}}} hasAuth: type: boolean description: If true, a username and password for login type authentication must be provided. @@ -1691,8 +1622,7 @@ components: type: string description: | The JSON payload sent to the update case URL to update the case. You can use variables to add Kibana Cases data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - examples: - - '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' + example: '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' updateIncidentMethod: type: string description: | @@ -1706,14 +1636,12 @@ components: type: string description: | The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. - examples: - - https://example.com/issue/{{{external.system.ID}}} + example: https://example.com/issue/{{{external.system.ID}}} viewIncidentUrl: type: string description: | The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL. - examples: - - https://testing-jira.atlassian.net/browse/{{{external.system.title}}} + example: https://testing-jira.atlassian.net/browse/{{{external.system.title}}} secrets_properties_cases_webhook: title: Connector secrets properties for Webhook - Case Management connector type: object @@ -1755,9 +1683,8 @@ components: clientId: description: | The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: - - string - - 'null' + type: string + nullable: true from: description: | The from address for all emails sent by the connector. It must be specified in `user@host-name` format. @@ -1772,9 +1699,8 @@ components: The host name of the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. type: string oauthTokenUrl: - type: - - string - - 'null' + type: string + nullable: true port: description: | The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. @@ -1797,9 +1723,8 @@ components: tenantId: description: | The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: - - string - - 'null' + type: string + nullable: true secrets_properties_email: title: Connector secrets properties for an email connector description: Defines secrets for connectors when type is `.email`. @@ -1883,9 +1808,8 @@ components: executionTimeField: description: A field that indicates when the document was indexed. default: null - type: - - string - - 'null' + type: string + nullable: true index: description: The Elasticsearch index to be written to. type: string @@ -1950,11 +1874,9 @@ components: properties: apiUrl: description: The PagerDuty event URL. - type: - - string - - 'null' - examples: - - https://events.pagerduty.com/v2/enqueue + type: string + nullable: true + example: https://events.pagerduty.com/v2/enqueue secrets_properties_pagerduty: title: Connector secrets properties for a PagerDuty connector description: Defines secrets for connectors when type is `.pagerduty`. @@ -2390,10 +2312,10 @@ components: properties: authType: type: string + nullable: true enum: - webhook-authentication-basic - webhook-authentication-ssl - - 'null' description: | The type of authentication to use: basic, SSL, or none. ca: @@ -2412,9 +2334,8 @@ components: description: | If `true`, a user name and password must be provided for login type authentication. headers: - type: - - object - - 'null' + type: object + nullable: true description: A set of key-value pairs sent as headers with the request. method: type: string @@ -2467,9 +2388,8 @@ components: configUrl: description: | The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`. - type: - - string - - 'null' + type: string + nullable: true usesBasic: description: Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`). type: boolean @@ -2952,9 +2872,8 @@ components: - name properties: config: - type: - - object - - 'null' + type: object + nullable: true connector_type_id: type: string description: The type of connector. @@ -3340,30 +3259,25 @@ components: is_deprecated: type: boolean description: Indicates whether the connector type is deprecated. - examples: - - false + example: false is_missing_secrets: type: boolean description: Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type. - examples: - - false + example: false is_preconfigured: type: boolean description: | Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. - examples: - - false + example: false is_system_action: type: boolean description: Indicates whether the connector is used for system actions. - examples: - - false + example: false referenced_by_count: type: integer description: | Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API. - examples: - - 2 + example: 2 connector_response_properties: title: Connector response properties description: The properties vary depending on the connector type. @@ -3459,8 +3373,7 @@ components: name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_cases_webhook' update_connector_request_d3security: @@ -3657,8 +3570,7 @@ components: name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_swimlane' update_connector_request_teams: @@ -3760,6 +3672,48 @@ components: - $ref: '#/components/schemas/update_connector_request_torq' - $ref: '#/components/schemas/update_connector_request_webhook' - $ref: '#/components/schemas/update_connector_request_xmatters' + features: + type: string + description: | + The feature that uses the connector. + enum: + - alerting + - cases + - generativeAIForSecurity + - generativeAIForObservability + - generativeAIForSearchPlayground + - siem + - uptime + connector_types: + title: Connector types + type: string + description: The type of connector. For example, `.email`, `.index`, `.jira`, `.opsgenie`, or `.server-log`. + enum: + - .bedrock + - .gemini + - .cases-webhook + - .d3security + - .email + - .gen-ai + - .index + - .jira + - .opsgenie + - .pagerduty + - .resilient + - .sentinelone + - .servicenow + - .servicenow-itom + - .servicenow-sir + - .server-log + - .slack + - .slack_api + - .swimlane + - .teams + - .tines + - .torq + - .webhook + - .xmatters + example: .server-log run_connector_params_acknowledge_resolve_pagerduty: title: PagerDuty connector parameters description: Test an action that acknowledges or resolves a PagerDuty alert. @@ -3876,13 +3830,11 @@ components: class: description: The class or type of the event. type: string - examples: - - cpu load + example: cpu load component: description: The component of the source machine that is responsible for the event. type: string - examples: - - eth0 + example: eth0 customDetails: description: Additional details to add to the event. type: object @@ -3899,8 +3851,7 @@ components: group: description: The logical grouping of components of a service. type: string - examples: - - app-stack + example: app-stack links: description: A list of links to add to the event. type: array @@ -4040,17 +3991,15 @@ components: - externalId properties: correlation_id: - type: - - 'null' - - string + type: string + nullable: true description: | An identifier that is assigned to the incident when it is created by the connector. NOTE: If you use the default value and the rule generates multiple alerts that use the same alert IDs, the latest open incident for this correlation ID is closed unless you specify the external ID. maxLength: 100 default: '{{rule.id}}:{{alert.id}}' externalId: - type: - - 'null' - - string + type: string + nullable: true description: The unique identifier (`incidentId`) for the incident in ServiceNow. run_connector_subaction_createalert: title: The createAlert subaction @@ -4085,9 +4034,9 @@ components: type: object description: The custom properties of the alert. additionalProperties: true - examples: - - key1: value1 - key2: value2 + example: + key1: value1 + key2: value2 entity: type: string description: The domain of the alert. For example, the application or server name. @@ -4185,8 +4134,7 @@ components: id: type: string description: The Jira issue type identifier. - examples: - - 10024 + example: 10024 run_connector_subaction_getchoices: title: The getChoices subaction type: object @@ -4244,8 +4192,7 @@ components: externalId: type: string description: The Jira, ServiceNow ITSM, or ServiceNow SecOps issue identifier. - examples: - - 71778 + example: 71778 run_connector_subaction_issue: title: The issue subaction type: object @@ -4266,8 +4213,7 @@ components: id: type: string description: The Jira issue identifier. - examples: - - 71778 + example: 71778 run_connector_subaction_issues: title: The issues subaction type: object @@ -4556,49 +4502,6 @@ components: issues: '#/components/schemas/run_connector_subaction_issues' issueTypes: '#/components/schemas/run_connector_subaction_issuetypes' pushToService: '#/components/schemas/run_connector_subaction_pushtoservice' - features: - type: string - description: | - The feature that uses the connector. - enum: - - alerting - - cases - - generativeAIForSecurity - - generativeAIForObservability - - generativeAIForSearchPlayground - - siem - - uptime - connector_types: - title: Connector types - type: string - description: The type of connector. For example, `.email`, `.index`, `.jira`, `.opsgenie`, or `.server-log`. - enum: - - .bedrock - - .gemini - - .cases-webhook - - .d3security - - .email - - .gen-ai - - .index - - .jira - - .opsgenie - - .pagerduty - - .resilient - - .sentinelone - - .servicenow - - .servicenow-itom - - .servicenow-sir - - .server-log - - .slack - - .slack_api - - .swimlane - - .teams - - .tines - - .torq - - .webhook - - .xmatters - examples: - - .server-log action_response_properties: title: Action response properties description: The properties vary depending on the action type. @@ -4749,37 +4652,60 @@ components: name: updated-connector config: index: updated-index - run_cases_webhook_connector_request: - summary: Run a Webhook - Case Management connector to create a case. + get_connectors_response: + summary: A list of connectors value: - params: - subAction: pushToService - subActionParams: - comments: - - commentId: 1 - comment: A comment about the incident. - incident: - title: Case title - description: Description of the incident. - tags: - - tag1 - - tag2 - severity: low - status: open - id: caseID - run_email_connector_request: - summary: Send an email message from an email connector. + - id: preconfigured-email-connector + name: my-preconfigured-email-notification + connector_type_id: .email + is_preconfigured: true + is_deprecated: false + referenced_by_count: 0 + is_system_action: false + - id: e07d0c80-8b8b-11ed-a780-3b746c987a81 + name: my-index-connector + config: + index: test-index + refresh: false + executionTimeField: null + connector_type_id: .index + is_preconfigured: false + is_deprecated: false + referenced_by_count: 2 + is_missing_secrets: false + is_system_action: false + get_connector_types_response: + summary: A list of connector types value: - params: - bcc: - - user1@example.com - cc: - - user2@example.com - - user3@example.com - message: Test email message. - subject: Test message subject - to: - - user4@example.com + - id: .swimlane + name: Swimlane + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: gold + supported_feature_ids: + - alerting + - cases + - siem + - id: .index + name: Index + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: basic + supported_feature_ids: + - alerting + - uptime + - siem + - id: .server-log + name: Server log + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: basic + supported_feature_ids: + - alerting + - uptime run_index_connector_request: summary: Run an index connector. value: @@ -4793,17 +4719,6 @@ components: value: params: subAction: issueTypes - run_pagerduty_connector_request: - summary: Run a PagerDuty connector to trigger an alert. - value: - params: - eventAction: trigger - summary: A brief event summary - links: - - href: http://example.com/pagerduty - text: An example link - customDetails: - my_data_1: test data run_server_log_connector_request: summary: Run a server log connector. value: @@ -4841,43 +4756,6 @@ components: caseId: '1000' caseName: Case name description: Description of the incident. - run_cases_webhook_connector_response: - summary: Response from a pushToService action for a Webhook - Case Management connector. - value: - connector_id: 1824b5b8-c005-4dcc-adac-57f92db46459 - data: - id: 100665 - title: TEST-29034 - url: https://example.com/browse/TEST-29034 - pushedDate: '2023-12-05T19:43:36.360Z' - comments: - - commentId: 1 - pushedDate: '2023-12-05T19:43:36.360Z' - status: ok - run_email_connector_response: - summary: Response for sending a message from an email connector. - value: - connector_id: 7fc7b9a0-ecc9-11ec-8736-e7d63118c907 - data: - accepted: - - user1@example.com - - user2@example.com - - user3@example.com - - user4@example.com - envelope: - from: tester@example.com - to: - - user1@example.com - - user2@example.com - - user3@example.com - - user4@example.com - envelopeTime: 8 - messageTime: 3 - messageSize: 729 - response: 250 Message queued as QzEXKcGJ - messageId: <08a92d29-642a-0706-750c-de5996bd5cf3@example.com> - rejected: [] - status: ok run_index_connector_response: summary: Response from running an index connector. value: @@ -4917,15 +4795,6 @@ components: - id: 10000 name: Epic status: ok - run_pagerduty_connector_response: - summary: Response from running a PagerDuty connector. - value: - connector_id: 45de9f70-954f-4608-b12a-db7cf808e49d - data: - dedup_key: 5115e138b26b484a81eaea779faa6016 - message: Event processed - status: success - status: ok run_server_log_connector_response: summary: Response from running a server log connector. value: @@ -5020,28 +4889,94 @@ components: - commentId: 1 pushedDate: '2022-09-08T16:52:27.865Z' status: ok - get_connectors_response: - summary: A list of connectors + run_cases_webhook_connector_request: + summary: Run a Webhook - Case Management connector to create a case. value: - - id: preconfigured-email-connector - name: my-preconfigured-email-notification - connector_type_id: .email - is_preconfigured: true - is_deprecated: false - referenced_by_count: 0 - is_system_action: false - - id: e07d0c80-8b8b-11ed-a780-3b746c987a81 - name: my-index-connector - config: - index: test-index - refresh: false - executionTimeField: null - connector_type_id: .index - is_preconfigured: false - is_deprecated: false - referenced_by_count: 2 - is_missing_secrets: false - is_system_action: false + params: + subAction: pushToService + subActionParams: + comments: + - commentId: 1 + comment: A comment about the incident. + incident: + title: Case title + description: Description of the incident. + tags: + - tag1 + - tag2 + severity: low + status: open + id: caseID + run_email_connector_request: + summary: Send an email message from an email connector. + value: + params: + bcc: + - user1@example.com + cc: + - user2@example.com + - user3@example.com + message: Test email message. + subject: Test message subject + to: + - user4@example.com + run_pagerduty_connector_request: + summary: Run a PagerDuty connector to trigger an alert. + value: + params: + eventAction: trigger + summary: A brief event summary + links: + - href: http://example.com/pagerduty + text: An example link + customDetails: + my_data_1: test data + run_cases_webhook_connector_response: + summary: Response from a pushToService action for a Webhook - Case Management connector. + value: + connector_id: 1824b5b8-c005-4dcc-adac-57f92db46459 + data: + id: 100665 + title: TEST-29034 + url: https://example.com/browse/TEST-29034 + pushedDate: '2023-12-05T19:43:36.360Z' + comments: + - commentId: 1 + pushedDate: '2023-12-05T19:43:36.360Z' + status: ok + run_email_connector_response: + summary: Response for sending a message from an email connector. + value: + connector_id: 7fc7b9a0-ecc9-11ec-8736-e7d63118c907 + data: + accepted: + - user1@example.com + - user2@example.com + - user3@example.com + - user4@example.com + envelope: + from: tester@example.com + to: + - user1@example.com + - user2@example.com + - user3@example.com + - user4@example.com + envelopeTime: 8 + messageTime: 3 + messageSize: 729 + response: 250 Message queued as QzEXKcGJ + messageId: <08a92d29-642a-0706-750c-de5996bd5cf3@example.com> + rejected: [] + status: ok + run_pagerduty_connector_response: + summary: Response from running a PagerDuty connector. + value: + connector_id: 45de9f70-954f-4608-b12a-db7cf808e49d + data: + dedup_key: 5115e138b26b484a81eaea779faa6016 + message: Event processed + status: success + status: ok get_connector_types_generativeai_response: summary: A list of connector types for the `generativeAI` feature. value: @@ -5076,38 +5011,6 @@ components: supported_feature_ids: - generativeAIForSecurity is_system_action_type: false - get_connector_types_response: - summary: A list of connector types - value: - - id: .swimlane - name: Swimlane - enabled: true - enabled_in_config: true - enabled_in_license: true - minimum_license_required: gold - supported_feature_ids: - - alerting - - cases - - siem - - id: .index - name: Index - enabled: true - enabled_in_config: true - enabled_in_license: true - minimum_license_required: basic - supported_feature_ids: - - alerting - - uptime - - siem - - id: .server-log - name: Server log - enabled: true - enabled_in_config: true - enabled_in_license: true - minimum_license_required: basic - supported_feature_ids: - - alerting - - uptime responses: '401': description: Authorization information is missing or invalid. @@ -5119,16 +5022,14 @@ components: properties: error: type: string - examples: - - Unauthorized + example: Unauthorized enum: - Unauthorized message: type: string statusCode: type: integer - examples: - - 401 + example: 401 enum: - 401 '404': @@ -5141,18 +5042,15 @@ components: properties: error: type: string - examples: - - Not Found + example: Not Found enum: - Not Found message: type: string - examples: - - Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found + example: Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found statusCode: type: integer - examples: - - 404 + example: 404 enum: - 404 200_actions: diff --git a/x-pack/plugins/actions/docs/openapi/bundled_serverless.json b/x-pack/plugins/actions/docs/openapi/bundled_serverless.json index 8de6f01f7f43a2..928dbbfd758d76 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled_serverless.json +++ b/x-pack/plugins/actions/docs/openapi/bundled_serverless.json @@ -1,5 +1,5 @@ { - "openapi": "3.1.0", + "openapi": "3.0.3", "info": { "title": "Connectors", "description": "OpenAPI schema for connectors in Serverless projects", @@ -36,7 +36,7 @@ "paths": { "/api/actions/connector": { "post": { - "summary": "Creates a connector.", + "summary": "Create a connector", "operationId": "createConnector", "tags": [ "connectors" @@ -103,7 +103,7 @@ }, "/api/actions/connector/{connectorId}": { "get": { - "summary": "Retrieves a connector by ID.", + "summary": "Get a connector information", "operationId": "getConnector", "tags": [ "connectors" @@ -138,7 +138,7 @@ } }, "delete": { - "summary": "Deletes a connector.", + "summary": "Delete a connector", "operationId": "deleteConnector", "tags": [ "connectors" @@ -164,7 +164,7 @@ } }, "post": { - "summary": "Creates a connector.", + "summary": "Create a connector", "operationId": "createConnectorId", "tags": [ "connectors" @@ -180,9 +180,7 @@ "required": true, "schema": { "type": "string", - "examples": [ - "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" - ] + "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" } } ], @@ -223,7 +221,7 @@ } }, "put": { - "summary": "Updates the attributes for a connector.", + "summary": "Update a connector", "operationId": "updateConnector", "tags": [ "connectors" @@ -276,7 +274,7 @@ }, "/api/actions/connectors": { "get": { - "summary": "Retrieves all connectors.", + "summary": "Get all connectors", "operationId": "getConnectors", "tags": [ "connectors" @@ -308,7 +306,7 @@ }, "/api/actions/connector_types": { "get": { - "summary": "Retrieves a list of all connector types.", + "summary": "Get all connector types", "operationId": "getConnectorTypes", "tags": [ "connectors" @@ -338,46 +336,34 @@ "enabled": { "type": "boolean", "description": "Indicates whether the connector type is enabled in Kibana.", - "examples": [ - true - ] + "example": true }, "enabled_in_config": { "type": "boolean", "description": "Indicates whether the connector type is enabled in the Kibana configuration file.", - "examples": [ - true - ] + "example": true }, "enabled_in_license": { "type": "boolean", "description": "Indicates whether the connector is enabled in the license.", - "examples": [ - true - ] + "example": true }, "id": { "$ref": "#/components/schemas/connector_types" }, "is_system_action_type": { "type": "boolean", - "examples": [ - false - ] + "example": false }, "minimum_license_required": { "type": "string", "description": "The license that is required to use the connector type.", - "examples": [ - "basic" - ] + "example": "basic" }, "name": { "type": "string", "description": "The name of the connector type.", - "examples": [ - "Index" - ] + "example": "Index" }, "supported_feature_ids": { "type": "array", @@ -385,12 +371,10 @@ "items": { "$ref": "#/components/schemas/features" }, - "examples": [ - [ - "alerting", - "cases", - "siem" - ] + "example": [ + "alerting", + "cases", + "siem" ] } } @@ -417,7 +401,7 @@ "type": "apiKey", "in": "header", "name": "Authorization", - "description": "e.g. Authorization: ApiKey base64AccessApiKey" + "description": "Serverless APIs support only key-based authentication. You must create an API key and use the encoded value in the request header. For example: 'Authorization: ApiKey base64AccessApiKey'.\n" } }, "parameters": { @@ -437,9 +421,7 @@ "required": true, "schema": { "type": "string", - "examples": [ - "df770e30-8b8b-11ed-a780-3b746c987a81" - ] + "example": "df770e30-8b8b-11ed-a780-3b746c987a81" } } }, @@ -464,16 +446,12 @@ "enum": [ ".bedrock" ], - "examples": [ - ".bedrock" - ] + "example": ".bedrock" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_bedrock" @@ -500,16 +478,12 @@ "enum": [ ".gemini" ], - "examples": [ - ".gemini" - ] + "example": ".gemini" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_gemini" @@ -535,16 +509,12 @@ "enum": [ ".cases-webhook" ], - "examples": [ - ".cases-webhook" - ] + "example": ".cases-webhook" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_cases_webhook" @@ -571,16 +541,12 @@ "enum": [ ".d3security" ], - "examples": [ - ".d3security" - ] + "example": ".d3security" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_d3security" @@ -607,16 +573,12 @@ "enum": [ ".email" ], - "examples": [ - ".email" - ] + "example": ".email" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_email" @@ -643,16 +605,12 @@ "enum": [ ".gen-ai" ], - "examples": [ - ".gen-ai" - ] + "example": ".gen-ai" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_genai" @@ -678,16 +636,12 @@ "enum": [ ".index" ], - "examples": [ - ".index" - ] + "example": ".index" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" } } }, @@ -711,16 +665,12 @@ "enum": [ ".jira" ], - "examples": [ - ".jira" - ] + "example": ".jira" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_jira" @@ -747,16 +697,12 @@ "enum": [ ".opsgenie" ], - "examples": [ - ".opsgenie" - ] + "example": ".opsgenie" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_opsgenie" @@ -783,16 +729,12 @@ "enum": [ ".pagerduty" ], - "examples": [ - ".pagerduty" - ] + "example": ".pagerduty" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_pagerduty" @@ -816,9 +758,7 @@ "connector_type_id": { "description": "The type of connector.", "type": "string", - "examples": [ - ".resilient" - ], + "example": ".resilient", "enum": [ ".resilient" ] @@ -826,9 +766,7 @@ "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_resilient" @@ -856,16 +794,12 @@ "enum": [ ".sentinelone" ], - "examples": [ - ".sentinelone" - ] + "example": ".sentinelone" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_sentinelone" @@ -887,16 +821,12 @@ "enum": [ ".server-log" ], - "examples": [ - ".server-log" - ] + "example": ".server-log" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" } } }, @@ -920,16 +850,12 @@ "enum": [ ".servicenow" ], - "examples": [ - ".servicenow" - ] + "example": ".servicenow" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -956,16 +882,12 @@ "enum": [ ".servicenow-itom" ], - "examples": [ - ".servicenow-itom" - ] + "example": ".servicenow-itom" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -992,16 +914,12 @@ "enum": [ ".servicenow-sir" ], - "examples": [ - ".servicenow-sir" - ] + "example": ".servicenow-sir" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_servicenow" @@ -1027,16 +945,12 @@ "enum": [ ".slack_api" ], - "examples": [ - ".slack_api" - ] + "example": ".slack_api" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_slack_api" @@ -1059,16 +973,12 @@ "enum": [ ".slack" ], - "examples": [ - ".slack" - ] + "example": ".slack" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_slack_webhook" @@ -1095,16 +1005,12 @@ "enum": [ ".swimlane" ], - "examples": [ - ".swimlane" - ] + "example": ".swimlane" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_swimlane" @@ -1127,16 +1033,12 @@ "enum": [ ".teams" ], - "examples": [ - ".teams" - ] + "example": ".teams" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_teams" @@ -1163,16 +1065,12 @@ "enum": [ ".tines" ], - "examples": [ - ".tines" - ] + "example": ".tines" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_tines" @@ -1199,16 +1097,12 @@ "enum": [ ".torq" ], - "examples": [ - ".torq" - ] + "example": ".torq" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_torq" @@ -1235,16 +1129,12 @@ "enum": [ ".webhook" ], - "examples": [ - ".webhook" - ] + "example": ".webhook" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_webhook" @@ -1271,16 +1161,12 @@ "enum": [ ".xmatters" ], - "examples": [ - ".xmatters" - ] + "example": ".xmatters" }, "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_xmatters" @@ -1386,9 +1272,7 @@ "createCommentJson": { "type": "string", "description": "A JSON payload sent to the create comment URL to create a case comment. You can use variables to add Kibana Cases data to the payload. The required variable is `case.comment`. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass.\n", - "examples": [ - "{\"body\": {{{case.comment}}}}" - ] + "example": "{\"body\": {{{case.comment}}}}" }, "createCommentMethod": { "type": "string", @@ -1403,16 +1287,12 @@ "createCommentUrl": { "type": "string", "description": "The REST API URL to create a case comment by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts.\n", - "examples": [ - "https://example.com/issue/{{{external.system.id}}}/comment" - ] + "example": "https://example.com/issue/{{{external.system.id}}}/comment" }, "createIncidentJson": { "type": "string", "description": "A JSON payload sent to the create case URL to create a case. You can use variables to add case data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review.\n", - "examples": [ - "{\"fields\": {\"summary\": {{{case.title}}},\"description\": {{{case.description}}},\"labels\": {{{case.tags}}}}}" - ] + "example": "{\"fields\": {\"summary\": {{{case.title}}},\"description\": {{{case.description}}},\"labels\": {{{case.tags}}}}}" }, "createIncidentMethod": { "type": "string", @@ -1439,9 +1319,7 @@ "getIncidentUrl": { "type": "string", "description": "The REST API URL to get the case by ID from the third-party system. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. You can use a variable to add the external system ID to the URL. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass.\n", - "examples": [ - "https://example.com/issue/{{{external.system.id}}}" - ] + "example": "https://example.com/issue/{{{external.system.id}}}" }, "hasAuth": { "type": "boolean", @@ -1455,9 +1333,7 @@ "updateIncidentJson": { "type": "string", "description": "The JSON payload sent to the update case URL to update the case. You can use variables to add Kibana Cases data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review.\n", - "examples": [ - "{\"fields\": {\"summary\": {{{case.title}}},\"description\": {{{case.description}}},\"labels\": {{{case.tags}}}}}" - ] + "example": "{\"fields\": {\"summary\": {{{case.title}}},\"description\": {{{case.description}}},\"labels\": {{{case.tags}}}}}" }, "updateIncidentMethod": { "type": "string", @@ -1472,16 +1348,12 @@ "updateIncidentUrl": { "type": "string", "description": "The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts.\n", - "examples": [ - "https://example.com/issue/{{{external.system.ID}}}" - ] + "example": "https://example.com/issue/{{{external.system.ID}}}" }, "viewIncidentUrl": { "type": "string", "description": "The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL.\n", - "examples": [ - "https://testing-jira.atlassian.net/browse/{{{external.system.title}}}" - ] + "example": "https://testing-jira.atlassian.net/browse/{{{external.system.title}}}" } } }, @@ -1537,10 +1409,8 @@ "properties": { "clientId": { "description": "The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true }, "from": { "description": "The from address for all emails sent by the connector. It must be specified in `user@host-name` format.\n", @@ -1556,10 +1426,8 @@ "type": "string" }, "oauthTokenUrl": { - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true }, "port": { "description": "The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. \n", @@ -1583,10 +1451,8 @@ }, "tenantId": { "description": "The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true } } }, @@ -1698,10 +1564,8 @@ "executionTimeField": { "description": "A field that indicates when the document was indexed.", "default": null, - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true }, "index": { "description": "The Elasticsearch index to be written to.", @@ -1787,13 +1651,9 @@ "properties": { "apiUrl": { "description": "The PagerDuty event URL.", - "type": [ - "string", - "null" - ], - "examples": [ - "https://events.pagerduty.com/v2/enqueue" - ] + "type": "string", + "nullable": true, + "example": "https://events.pagerduty.com/v2/enqueue" } } }, @@ -2363,10 +2223,10 @@ "properties": { "authType": { "type": "string", + "nullable": true, "enum": [ "webhook-authentication-basic", - "webhook-authentication-ssl", - "null" + "webhook-authentication-ssl" ], "description": "The type of authentication to use: basic, SSL, or none.\n" }, @@ -2387,10 +2247,8 @@ "description": "If `true`, a user name and password must be provided for login type authentication.\n" }, "headers": { - "type": [ - "object", - "null" - ], + "type": "object", + "nullable": true, "description": "A set of key-value pairs sent as headers with the request." }, "method": { @@ -2452,10 +2310,8 @@ "properties": { "configUrl": { "description": "The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`.\n", - "type": [ - "string", - "null" - ] + "type": "string", + "nullable": true }, "usesBasic": { "description": "Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`).", @@ -3152,10 +3008,8 @@ ], "properties": { "config": { - "type": [ - "object", - "null" - ] + "type": "object", + "nullable": true }, "connector_type_id": { "type": "string", @@ -3695,37 +3549,27 @@ "is_deprecated": { "type": "boolean", "description": "Indicates whether the connector type is deprecated.", - "examples": [ - false - ] + "example": false }, "is_missing_secrets": { "type": "boolean", "description": "Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type.", - "examples": [ - false - ] + "example": false }, "is_preconfigured": { "type": "boolean", "description": "Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. \n", - "examples": [ - false - ] + "example": false }, "is_system_action": { "type": "boolean", "description": "Indicates whether the connector is used for system actions.", - "examples": [ - false - ] + "example": false }, "referenced_by_count": { "type": "integer", "description": "Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API.\n", - "examples": [ - 2 - ] + "example": 2 }, "connector_response_properties": { "title": "Connector response properties", @@ -3888,9 +3732,7 @@ "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_cases_webhook" @@ -4167,9 +4009,7 @@ "name": { "type": "string", "description": "The display name for the connector.", - "examples": [ - "my-connector" - ] + "example": "my-connector" }, "secrets": { "$ref": "#/components/schemas/secrets_properties_swimlane" @@ -4395,9 +4235,7 @@ ".webhook", ".xmatters" ], - "examples": [ - ".server-log" - ] + "example": ".server-log" } }, "examples": { @@ -4646,9 +4484,7 @@ "properties": { "error": { "type": "string", - "examples": [ - "Unauthorized" - ], + "example": "Unauthorized", "enum": [ "Unauthorized" ] @@ -4658,9 +4494,7 @@ }, "statusCode": { "type": "integer", - "examples": [ - 401 - ], + "example": 401, "enum": [ 401 ] @@ -4680,24 +4514,18 @@ "properties": { "error": { "type": "string", - "examples": [ - "Not Found" - ], + "example": "Not Found", "enum": [ "Not Found" ] }, "message": { "type": "string", - "examples": [ - "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" - ] + "example": "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" }, "statusCode": { "type": "integer", - "examples": [ - 404 - ], + "example": 404, "enum": [ 404 ] diff --git a/x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml b/x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml index ab5cf28a738486..4fdc184e3fb90d 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml +++ b/x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml @@ -1,4 +1,4 @@ -openapi: 3.1.0 +openapi: 3.0.3 info: title: Connectors description: OpenAPI schema for connectors in Serverless projects @@ -21,7 +21,7 @@ tags: paths: /api/actions/connector: post: - summary: Creates a connector. + summary: Create a connector operationId: createConnector tags: - connectors @@ -62,7 +62,7 @@ paths: $ref: '#/components/responses/401' /api/actions/connector/{connectorId}: get: - summary: Retrieves a connector by ID. + summary: Get a connector information operationId: getConnector tags: - connectors @@ -83,7 +83,7 @@ paths: '404': $ref: '#/components/responses/404' delete: - summary: Deletes a connector. + summary: Delete a connector operationId: deleteConnector tags: - connectors @@ -98,7 +98,7 @@ paths: '404': $ref: '#/components/responses/404' post: - summary: Creates a connector. + summary: Create a connector operationId: createConnectorId tags: - connectors @@ -111,8 +111,7 @@ paths: required: true schema: type: string - examples: - - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: @@ -135,7 +134,7 @@ paths: '401': $ref: '#/components/responses/401' put: - summary: Updates the attributes for a connector. + summary: Update a connector operationId: updateConnector tags: - connectors @@ -166,7 +165,7 @@ paths: $ref: '#/components/responses/404' /api/actions/connectors: get: - summary: Retrieves all connectors. + summary: Get all connectors operationId: getConnectors tags: - connectors @@ -186,7 +185,7 @@ paths: $ref: '#/components/responses/401' /api/actions/connector_types: get: - summary: Retrieves a list of all connector types. + summary: Get all connector types operationId: getConnectorTypes tags: - connectors @@ -211,43 +210,37 @@ paths: enabled: type: boolean description: Indicates whether the connector type is enabled in Kibana. - examples: - - true + example: true enabled_in_config: type: boolean description: Indicates whether the connector type is enabled in the Kibana configuration file. - examples: - - true + example: true enabled_in_license: type: boolean description: Indicates whether the connector is enabled in the license. - examples: - - true + example: true id: $ref: '#/components/schemas/connector_types' is_system_action_type: type: boolean - examples: - - false + example: false minimum_license_required: type: string description: The license that is required to use the connector type. - examples: - - basic + example: basic name: type: string description: The name of the connector type. - examples: - - Index + example: Index supported_feature_ids: type: array description: The features that are supported by the connector type. items: $ref: '#/components/schemas/features' - examples: - - - alerting - - cases - - siem + example: + - alerting + - cases + - siem examples: getConnectorTypesServerlessResponse: $ref: '#/components/examples/get_connector_types_generativeai_response' @@ -259,7 +252,8 @@ components: type: apiKey in: header name: Authorization - description: 'e.g. Authorization: ApiKey base64AccessApiKey' + description: | + Serverless APIs support only key-based authentication. You must create an API key and use the encoded value in the request header. For example: 'Authorization: ApiKey base64AccessApiKey'. parameters: kbn_xsrf: schema: @@ -275,8 +269,7 @@ components: required: true schema: type: string - examples: - - df770e30-8b8b-11ed-a780-3b746c987a81 + example: df770e30-8b8b-11ed-a780-3b746c987a81 schemas: create_connector_request_bedrock: title: Create Amazon Bedrock connector request @@ -295,13 +288,11 @@ components: description: The type of connector. enum: - .bedrock - examples: - - .bedrock + example: .bedrock name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_bedrock' create_connector_request_gemini: @@ -321,13 +312,11 @@ components: description: The type of connector. enum: - .gemini - examples: - - .gemini + example: .gemini name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_gemini' create_connector_request_cases_webhook: @@ -347,13 +336,11 @@ components: description: The type of connector. enum: - .cases-webhook - examples: - - .cases-webhook + example: .cases-webhook name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_cases_webhook' create_connector_request_d3security: @@ -374,13 +361,11 @@ components: description: The type of connector. enum: - .d3security - examples: - - .d3security + example: .d3security name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_d3security' create_connector_request_email: @@ -401,13 +386,11 @@ components: description: The type of connector. enum: - .email - examples: - - .email + example: .email name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_email' create_connector_request_genai: @@ -428,13 +411,11 @@ components: description: The type of connector. enum: - .gen-ai - examples: - - .gen-ai + example: .gen-ai name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_genai' create_connector_request_index: @@ -453,13 +434,11 @@ components: description: The type of connector. enum: - .index - examples: - - .index + example: .index name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector create_connector_request_jira: title: Create Jira connector request description: The Jira connector uses the REST API v2 to create Jira issues. @@ -477,13 +456,11 @@ components: description: The type of connector. enum: - .jira - examples: - - .jira + example: .jira name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_jira' create_connector_request_opsgenie: @@ -503,13 +480,11 @@ components: description: The type of connector. enum: - .opsgenie - examples: - - .opsgenie + example: .opsgenie name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_opsgenie' create_connector_request_pagerduty: @@ -530,13 +505,11 @@ components: description: The type of connector. enum: - .pagerduty - examples: - - .pagerduty + example: .pagerduty name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_pagerduty' create_connector_request_resilient: @@ -554,15 +527,13 @@ components: connector_type_id: description: The type of connector. type: string - examples: - - .resilient + example: .resilient enum: - .resilient name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_resilient' create_connector_request_sentinelone: @@ -584,13 +555,11 @@ components: description: The type of connector. enum: - .sentinelone - examples: - - .sentinelone + example: .sentinelone name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_sentinelone' create_connector_request_serverlog: @@ -606,13 +575,11 @@ components: description: The type of connector. enum: - .server-log - examples: - - .server-log + example: .server-log name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector create_connector_request_servicenow: title: Create ServiceNow ITSM connector request description: | @@ -631,13 +598,11 @@ components: description: The type of connector. enum: - .servicenow - examples: - - .servicenow + example: .servicenow name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' create_connector_request_servicenow_itom: @@ -658,13 +623,11 @@ components: description: The type of connector. enum: - .servicenow-itom - examples: - - .servicenow-itom + example: .servicenow-itom name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' create_connector_request_servicenow_sir: @@ -685,13 +648,11 @@ components: description: The type of connector. enum: - .servicenow-sir - examples: - - .servicenow-sir + example: .servicenow-sir name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_servicenow' create_connector_request_slack_api: @@ -710,13 +671,11 @@ components: description: The type of connector. enum: - .slack_api - examples: - - .slack_api + example: .slack_api name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack_api' create_connector_request_slack_webhook: @@ -733,13 +692,11 @@ components: description: The type of connector. enum: - .slack - examples: - - .slack + example: .slack name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_slack_webhook' create_connector_request_swimlane: @@ -759,13 +716,11 @@ components: description: The type of connector. enum: - .swimlane - examples: - - .swimlane + example: .swimlane name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_swimlane' create_connector_request_teams: @@ -782,13 +737,11 @@ components: description: The type of connector. enum: - .teams - examples: - - .teams + example: .teams name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_teams' create_connector_request_tines: @@ -809,13 +762,11 @@ components: description: The type of connector. enum: - .tines - examples: - - .tines + example: .tines name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_tines' create_connector_request_torq: @@ -836,13 +787,11 @@ components: description: The type of connector. enum: - .torq - examples: - - .torq + example: .torq name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_torq' create_connector_request_webhook: @@ -863,13 +812,11 @@ components: description: The type of connector. enum: - .webhook - examples: - - .webhook + example: .webhook name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_webhook' create_connector_request_xmatters: @@ -890,13 +837,11 @@ components: description: The type of connector. enum: - .xmatters - examples: - - .xmatters + example: .xmatters name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_xmatters' config_properties_bedrock: @@ -978,8 +923,7 @@ components: type: string description: | A JSON payload sent to the create comment URL to create a case comment. You can use variables to add Kibana Cases data to the payload. The required variable is `case.comment`. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - examples: - - '{"body": {{{case.comment}}}}' + example: '{"body": {{{case.comment}}}}' createCommentMethod: type: string description: | @@ -993,14 +937,12 @@ components: type: string description: | The REST API URL to create a case comment by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts. - examples: - - https://example.com/issue/{{{external.system.id}}}/comment + example: https://example.com/issue/{{{external.system.id}}}/comment createIncidentJson: type: string description: | A JSON payload sent to the create case URL to create a case. You can use variables to add case data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - examples: - - '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' + example: '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' createIncidentMethod: type: string description: | @@ -1024,8 +966,7 @@ components: type: string description: | The REST API URL to get the case by ID from the third-party system. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. You can use a variable to add the external system ID to the URL. Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - examples: - - https://example.com/issue/{{{external.system.id}}} + example: https://example.com/issue/{{{external.system.id}}} hasAuth: type: boolean description: If true, a username and password for login type authentication must be provided. @@ -1038,8 +979,7 @@ components: type: string description: | The JSON payload sent to the update case URL to update the case. You can use variables to add Kibana Cases data to the payload. Required variables are `case.title` and `case.description`. Due to Mustache template variables (which is the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated when you create the connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - examples: - - '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' + example: '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' updateIncidentMethod: type: string description: | @@ -1053,14 +993,12 @@ components: type: string description: | The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. - examples: - - https://example.com/issue/{{{external.system.ID}}} + example: https://example.com/issue/{{{external.system.ID}}} viewIncidentUrl: type: string description: | The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL. - examples: - - https://testing-jira.atlassian.net/browse/{{{external.system.title}}} + example: https://testing-jira.atlassian.net/browse/{{{external.system.title}}} secrets_properties_cases_webhook: title: Connector secrets properties for Webhook - Case Management connector type: object @@ -1102,9 +1040,8 @@ components: clientId: description: | The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: - - string - - 'null' + type: string + nullable: true from: description: | The from address for all emails sent by the connector. It must be specified in `user@host-name` format. @@ -1119,9 +1056,8 @@ components: The host name of the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. type: string oauthTokenUrl: - type: - - string - - 'null' + type: string + nullable: true port: description: | The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. @@ -1144,9 +1080,8 @@ components: tenantId: description: | The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: - - string - - 'null' + type: string + nullable: true secrets_properties_email: title: Connector secrets properties for an email connector description: Defines secrets for connectors when type is `.email`. @@ -1230,9 +1165,8 @@ components: executionTimeField: description: A field that indicates when the document was indexed. default: null - type: - - string - - 'null' + type: string + nullable: true index: description: The Elasticsearch index to be written to. type: string @@ -1297,11 +1231,9 @@ components: properties: apiUrl: description: The PagerDuty event URL. - type: - - string - - 'null' - examples: - - https://events.pagerduty.com/v2/enqueue + type: string + nullable: true + example: https://events.pagerduty.com/v2/enqueue secrets_properties_pagerduty: title: Connector secrets properties for a PagerDuty connector description: Defines secrets for connectors when type is `.pagerduty`. @@ -1737,10 +1669,10 @@ components: properties: authType: type: string + nullable: true enum: - webhook-authentication-basic - webhook-authentication-ssl - - 'null' description: | The type of authentication to use: basic, SSL, or none. ca: @@ -1759,9 +1691,8 @@ components: description: | If `true`, a user name and password must be provided for login type authentication. headers: - type: - - object - - 'null' + type: object + nullable: true description: A set of key-value pairs sent as headers with the request. method: type: string @@ -1814,9 +1745,8 @@ components: configUrl: description: | The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`. - type: - - string - - 'null' + type: string + nullable: true usesBasic: description: Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`). type: boolean @@ -2299,9 +2229,8 @@ components: - name properties: config: - type: - - object - - 'null' + type: object + nullable: true connector_type_id: type: string description: The type of connector. @@ -2687,30 +2616,25 @@ components: is_deprecated: type: boolean description: Indicates whether the connector type is deprecated. - examples: - - false + example: false is_missing_secrets: type: boolean description: Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type. - examples: - - false + example: false is_preconfigured: type: boolean description: | Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. - examples: - - false + example: false is_system_action: type: boolean description: Indicates whether the connector is used for system actions. - examples: - - false + example: false referenced_by_count: type: integer description: | Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API. - examples: - - 2 + example: 2 connector_response_properties: title: Connector response properties description: The properties vary depending on the connector type. @@ -2806,8 +2730,7 @@ components: name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_cases_webhook' update_connector_request_d3security: @@ -3004,8 +2927,7 @@ components: name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: '#/components/schemas/secrets_properties_swimlane' update_connector_request_teams: @@ -3148,8 +3070,7 @@ components: - .torq - .webhook - .xmatters - examples: - - .server-log + example: .server-log examples: create_email_connector_request: summary: Create an email connector. @@ -3345,16 +3266,14 @@ components: properties: error: type: string - examples: - - Unauthorized + example: Unauthorized enum: - Unauthorized message: type: string statusCode: type: integer - examples: - - 401 + example: 401 enum: - 401 '404': @@ -3367,17 +3286,14 @@ components: properties: error: type: string - examples: - - Not Found + example: Not Found enum: - Not Found message: type: string - examples: - - Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found + example: Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found statusCode: type: integer - examples: - - 404 + example: 404 enum: - 404 diff --git a/x-pack/plugins/actions/docs/openapi/components/parameters/action_id.yaml b/x-pack/plugins/actions/docs/openapi/components/parameters/action_id.yaml index acbc6ab5acd63d..3ee0b642c9dee4 100644 --- a/x-pack/plugins/actions/docs/openapi/components/parameters/action_id.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/parameters/action_id.yaml @@ -4,5 +4,4 @@ description: An identifier for the action. required: true schema: type: string - examples: - - c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad + example: c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad diff --git a/x-pack/plugins/actions/docs/openapi/components/parameters/connector_id.yaml b/x-pack/plugins/actions/docs/openapi/components/parameters/connector_id.yaml index fdf1487e626a86..d98c2cec803ff9 100644 --- a/x-pack/plugins/actions/docs/openapi/components/parameters/connector_id.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/parameters/connector_id.yaml @@ -4,5 +4,4 @@ description: An identifier for the connector. required: true schema: type: string - examples: - - df770e30-8b8b-11ed-a780-3b746c987a81 + example: df770e30-8b8b-11ed-a780-3b746c987a81 diff --git a/x-pack/plugins/actions/docs/openapi/components/parameters/space_id.yaml b/x-pack/plugins/actions/docs/openapi/components/parameters/space_id.yaml index 45787e844caec4..0a9fba457e3e74 100644 --- a/x-pack/plugins/actions/docs/openapi/components/parameters/space_id.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/parameters/space_id.yaml @@ -4,5 +4,4 @@ description: An identifier for the space. If `/s/` and the identifier are omitte required: true schema: type: string - examples: - - default + example: default diff --git a/x-pack/plugins/actions/docs/openapi/components/responses/400.yaml b/x-pack/plugins/actions/docs/openapi/components/responses/400.yaml index 4f8890737ff407..263623dd1fb4cb 100644 --- a/x-pack/plugins/actions/docs/openapi/components/responses/400.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/responses/400.yaml @@ -6,13 +6,10 @@ content: properties: error: type: string - examples: - - Bad Request + example: Bad Request message: type: string - examples: - - "error validating action type config: [index]: expected value of type [string] but got [undefined]" + example: "error validating action type config: [index]: expected value of type [string] but got [undefined]" statusCode: type: integer - examples: - - 400 \ No newline at end of file + example: 400 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/responses/401.yaml b/x-pack/plugins/actions/docs/openapi/components/responses/401.yaml index 78b77b3ab5f432..ff5cbfd4c27681 100644 --- a/x-pack/plugins/actions/docs/openapi/components/responses/401.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/responses/401.yaml @@ -7,15 +7,13 @@ content: properties: error: type: string - examples: - - Unauthorized + example: Unauthorized enum: - Unauthorized message: type: string statusCode: type: integer - examples: - - 401 + example: 401 enum: - 401 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/responses/404.yaml b/x-pack/plugins/actions/docs/openapi/components/responses/404.yaml index d4cf816f5903c1..56964c6015c85d 100644 --- a/x-pack/plugins/actions/docs/openapi/components/responses/404.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/responses/404.yaml @@ -7,17 +7,14 @@ content: properties: error: type: string - examples: - - Not Found + example: Not Found enum: - Not Found message: type: string - examples: - - "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" + example: "Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not found" statusCode: type: integer - examples: - - 404 + example: 404 enum: - 404 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_cases_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_cases_webhook.yaml index a452a1fdfd0601..b2a1ea8848ba76 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_cases_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_cases_webhook.yaml @@ -22,8 +22,7 @@ properties: connector. The JSON is validated once the Mustache variables have been placed when the REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - examples: - - '{"body": {{{case.comment}}}}' + example: '{"body": {{{case.comment}}}}' createCommentMethod: type: string description: > @@ -41,8 +40,7 @@ properties: You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts setting`, add the hostname to the allowed hosts. - examples: - - https://example.com/issue/{{{external.system.id}}}/comment + example: https://example.com/issue/{{{external.system.id}}}/comment createIncidentJson: type: string description: > @@ -54,8 +52,7 @@ properties: connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - examples: - - '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' + example: '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' createIncidentMethod: type: string description: > @@ -89,8 +86,7 @@ properties: variables have been placed when REST method runs. Manually ensure that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. - examples: - - https://example.com/issue/{{{external.system.id}}} + example: https://example.com/issue/{{{external.system.id}}} hasAuth: type: boolean description: If true, a username and password for login type authentication must be provided. @@ -111,8 +107,7 @@ properties: connector. The JSON is validated after the Mustache variables have been placed when REST method runs. Manually ensure that the JSON is valid to avoid future validation errors; disregard Mustache variables during your review. - examples: - - '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' + example: '{"fields": {"summary": {{{case.title}}},"description": {{{case.description}}},"labels": {{{case.tags}}}}}' updateIncidentMethod: type: string description: > @@ -129,14 +124,12 @@ properties: The REST API URL to update the case by ID in the third-party system. You can use a variable to add the external system ID to the URL. If you are using the `xpack.actions.allowedHosts` setting, add the hostname to the allowed hosts. - examples: - - https://example.com/issue/{{{external.system.ID}}} + example: https://example.com/issue/{{{external.system.ID}}} viewIncidentUrl: type: string description: > The URL to view the case in the external system. You can use variables to add the external system ID or external system title to the URL. - examples: - - https://testing-jira.atlassian.net/browse/{{{external.system.title}}} + example: https://testing-jira.atlassian.net/browse/{{{external.system.title}}} diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml index 202f4022a6fbd1..6d3618e2bba27b 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml @@ -8,9 +8,8 @@ properties: description: > The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: - - "string" - - "null" + type: string + nullable: true from: description: > The from address for all emails sent by the connector. It must be specified in `user@host-name` format. @@ -28,9 +27,8 @@ properties: type: string oauthTokenUrl: # description: TBD - type: - - "string" - - "null" + type: string + nullable: true port: description: > The port to connect to on the service provider. @@ -57,6 +55,5 @@ properties: description: > The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. - type: - - "string" - - "null" \ No newline at end of file + type: string + nullable: true \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_index.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_index.yaml index f6d3af59b49378..6c335b166d20ac 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_index.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_index.yaml @@ -7,9 +7,8 @@ properties: executionTimeField: description: A field that indicates when the document was indexed. default: null - type: - - "string" - - "null" + type: string + nullable: true index: description: The Elasticsearch index to be written to. type: string diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_pagerduty.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_pagerduty.yaml index bfbec7b46190b7..562557f548ece1 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_pagerduty.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_pagerduty.yaml @@ -4,8 +4,6 @@ type: object properties: apiUrl: description: The PagerDuty event URL. - type: - - "string" - - "null" - examples: - - https://events.pagerduty.com/v2/enqueue \ No newline at end of file + type: string + nullable: true + example: https://events.pagerduty.com/v2/enqueue \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_webhook.yaml index 601d4106665765..bf073419a4e096 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_webhook.yaml @@ -4,10 +4,10 @@ type: object properties: authType: type: string + nullable: true enum: - webhook-authentication-basic - webhook-authentication-ssl - - "null" description: > The type of authentication to use: basic, SSL, or none. ca: @@ -27,9 +27,8 @@ properties: description: > If `true`, a user name and password must be provided for login type authentication. headers: - type: - - "object" - - "null" + type: object + nullable: true description: A set of key-value pairs sent as headers with the request. method: type: string diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_xmatters.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_xmatters.yaml index 3393c11ecd90dd..350e96f3aa63d0 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_xmatters.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_xmatters.yaml @@ -6,9 +6,8 @@ properties: description: > The request URL for the Elastic Alerts trigger in xMatters. It is applicable only when `usesBasic` is `true`. - type: - - "string" - - "null" + type: string + nullable: true usesBasic: description: Specifies whether the connector uses HTTP basic authentication (`true`) or URL authentication (`false`). type: boolean diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_serverlog.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_serverlog.yaml index da741478864b43..a397e668102a64 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_serverlog.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_response_properties_serverlog.yaml @@ -8,9 +8,8 @@ required: - name properties: config: - type: - - "object" - - "null" + type: object + nullable: true connector_type_id: type: string description: The type of connector. diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml index f202efc087b008..db6262f04c0107 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/connector_types.yaml @@ -26,5 +26,4 @@ enum: - .torq - .webhook - .xmatters -examples: - - .server-log \ No newline at end of file +example: .server-log \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_bedrock.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_bedrock.yaml index e8feecb0051cd1..2acc21bfbfac74 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_bedrock.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_bedrock.yaml @@ -14,12 +14,10 @@ properties: description: The type of connector. enum: - .bedrock - examples: - - .bedrock + example: .bedrock name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_bedrock.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_cases_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_cases_webhook.yaml index 0cd030d7408097..bcbe840c03513c 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_cases_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_cases_webhook.yaml @@ -15,12 +15,10 @@ properties: description: The type of connector. enum: - .cases-webhook - examples: - - .cases-webhook + example: .cases-webhook name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_cases_webhook.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_d3security.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_d3security.yaml index 6b5389cc80f310..39cdda80b7dd26 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_d3security.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_d3security.yaml @@ -15,12 +15,10 @@ properties: description: The type of connector. enum: - .d3security - examples: - - .d3security + example: .d3security name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_d3security.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_email.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_email.yaml index 1f1c6c079770a2..89f0b79c4e74be 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_email.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_email.yaml @@ -18,12 +18,10 @@ properties: description: The type of connector. enum: - .email - examples: - - .email + example: .email name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_email.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_gemini.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_gemini.yaml index b9f4a651003c01..5b9cc31ae37878 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_gemini.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_gemini.yaml @@ -14,12 +14,10 @@ properties: description: The type of connector. enum: - .gemini - examples: - - .gemini + example: .gemini name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_gemini.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_genai.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_genai.yaml index 725f842f910930..95d65bdb809191 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_genai.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_genai.yaml @@ -16,12 +16,10 @@ properties: description: The type of connector. enum: - .gen-ai - examples: - - .gen-ai + example: .gen-ai name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_genai.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_index.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_index.yaml index ad8e9be9a41dce..26d6e118c1fe8d 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_index.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_index.yaml @@ -13,10 +13,8 @@ properties: description: The type of connector. enum: - .index - examples: - - .index + example: .index name: type: string description: The display name for the connector. - examples: - - my-connector \ No newline at end of file + example: my-connector \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_jira.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_jira.yaml index 95ccaa5b2ec6fe..5b6077e875b24c 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_jira.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_jira.yaml @@ -14,12 +14,10 @@ properties: description: The type of connector. enum: - .jira - examples: - - .jira + example: .jira name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_jira.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_opsgenie.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_opsgenie.yaml index 51c29f5cdd8fd0..6de1296dac43cd 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_opsgenie.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_opsgenie.yaml @@ -14,12 +14,10 @@ properties: description: The type of connector. enum: - .opsgenie - examples: - - .opsgenie + example: .opsgenie name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_opsgenie.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_pagerduty.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_pagerduty.yaml index 66ffc61d30f302..498488299afd37 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_pagerduty.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_pagerduty.yaml @@ -16,12 +16,10 @@ properties: description: The type of connector. enum: - .pagerduty - examples: - - .pagerduty + example: .pagerduty name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_pagerduty.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_resilient.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_resilient.yaml index 60467336c0d9aa..c3f766625b7da0 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_resilient.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_resilient.yaml @@ -12,14 +12,12 @@ properties: connector_type_id: description: The type of connector. type: string - examples: - - .resilient + example: .resilient enum: - .resilient name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_resilient.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_sentinelone.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_sentinelone.yaml index d741f9b35af353..0d2809f24d78b2 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_sentinelone.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_sentinelone.yaml @@ -18,12 +18,10 @@ properties: description: The type of connector. enum: - .sentinelone - examples: - - .sentinelone + example: .sentinelone name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_sentinelone.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_serverlog.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_serverlog.yaml index 0cb85403663c6f..eac0a0d65b69f3 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_serverlog.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_serverlog.yaml @@ -10,10 +10,8 @@ properties: description: The type of connector. enum: - .server-log - examples: - - .server-log + example: .server-log name: type: string description: The display name for the connector. - examples: - - my-connector \ No newline at end of file + example: my-connector \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow.yaml index b0f35483cc39f1..e03303dcada4fb 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow.yaml @@ -16,12 +16,10 @@ properties: description: The type of connector. enum: - .servicenow - examples: - - .servicenow + example: .servicenow name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_servicenow.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_itom.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_itom.yaml index bfbeb231ca7dc4..70a4c05c96522e 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_itom.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_itom.yaml @@ -16,12 +16,10 @@ properties: description: The type of connector. enum: - .servicenow-itom - examples: - - .servicenow-itom + example: .servicenow-itom name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_servicenow.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_sir.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_sir.yaml index 37519eb63f27ba..4d247c456f3e62 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_sir.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_servicenow_sir.yaml @@ -16,12 +16,10 @@ properties: description: The type of connector. enum: - .servicenow-sir - examples: - - .servicenow-sir + example: .servicenow-sir name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_servicenow.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_api.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_api.yaml index 2044087fba78c4..3870f418606a20 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_api.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_api.yaml @@ -13,12 +13,10 @@ properties: description: The type of connector. enum: - .slack_api - examples: - - .slack_api + example: .slack_api name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_slack_api.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_webhook.yaml index 3e884daa6e3b89..1c046cc3f000cf 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_slack_webhook.yaml @@ -11,12 +11,10 @@ properties: description: The type of connector. enum: - .slack - examples: - - .slack + example: .slack name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_slack_webhook.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_swimlane.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_swimlane.yaml index 633438a721ee93..3de4f5ecbcceff 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_swimlane.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_swimlane.yaml @@ -14,12 +14,10 @@ properties: description: The type of connector. enum: - .swimlane - examples: - - .swimlane + example: .swimlane name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_swimlane.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_teams.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_teams.yaml index 787f057c09ce60..5e0d449bf5546c 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_teams.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_teams.yaml @@ -11,12 +11,10 @@ properties: description: The type of connector. enum: - .teams - examples: - - .teams + example: .teams name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_teams.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_tines.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_tines.yaml index c5333c8acc4791..224c3e03c43632 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_tines.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_tines.yaml @@ -15,12 +15,10 @@ properties: description: The type of connector. enum: - .tines - examples: - - .tines + example: .tines name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_tines.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml index a4ab3cc92aa0d4..934f9c9c1b395f 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_torq.yaml @@ -15,12 +15,10 @@ properties: description: The type of connector. enum: - .torq - examples: - - .torq + example: .torq name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_torq.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_webhook.yaml index 30e9663da8d999..e0ead115d48dc6 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_webhook.yaml @@ -15,12 +15,10 @@ properties: description: The type of connector. enum: - .webhook - examples: - - .webhook + example: .webhook name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_webhook.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_xmatters.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_xmatters.yaml index 753888b16ae5ee..13213d39561b28 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_xmatters.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/create_connector_request_xmatters.yaml @@ -16,12 +16,10 @@ properties: description: The type of connector. enum: - .xmatters - examples: - - .xmatters + example: .xmatters name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_xmatters.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/is_deprecated.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/is_deprecated.yaml index ac0a26102eed12..75fb1efe2f589a 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/is_deprecated.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/is_deprecated.yaml @@ -1,4 +1,3 @@ type: boolean description: Indicates whether the connector type is deprecated. -examples: - - false \ No newline at end of file +example: false \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/is_missing_secrets.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/is_missing_secrets.yaml index a7ad3f9542b3fe..cad03a44f8629a 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/is_missing_secrets.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/is_missing_secrets.yaml @@ -1,4 +1,3 @@ type: boolean description: Indicates whether secrets are missing for the connector. Secrets configuration properties vary depending on the connector type. -examples: - - false \ No newline at end of file +example: false \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/is_preconfigured.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/is_preconfigured.yaml index d3f711c229399e..e38741c83718eb 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/is_preconfigured.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/is_preconfigured.yaml @@ -2,5 +2,4 @@ type: boolean description: > Indicates whether it is a preconfigured connector. If true, the `config` and `is_missing_secrets` properties are omitted from the response. -examples: - - false \ No newline at end of file +example: false \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/is_system_action.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/is_system_action.yaml index 5a78f4676646f3..fd0dd06ef5fff8 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/is_system_action.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/is_system_action.yaml @@ -1,4 +1,3 @@ type: boolean description: Indicates whether the connector is used for system actions. -examples: - - false \ No newline at end of file +example: false \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/referenced_by_count.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/referenced_by_count.yaml index 0a65bf9a854ff8..61579fa3dc6ce3 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/referenced_by_count.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/referenced_by_count.yaml @@ -3,5 +3,4 @@ description: > Indicates the number of saved objects that reference the connector. If `is_preconfigured` is true, this value is not calculated. This property is returned only by the get all connectors API. -examples: - - 2 \ No newline at end of file +example: 2 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_trigger_pagerduty.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_trigger_pagerduty.yaml index 75a59af1562644..71410725cbeae1 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_trigger_pagerduty.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_params_trigger_pagerduty.yaml @@ -7,13 +7,11 @@ properties: class: description: The class or type of the event. type: string - examples: - - cpu load + example: cpu load component: description: The component of the source machine that is responsible for the event. type: string - examples: - - eth0 + example: eth0 customDetails: description: Additional details to add to the event. type: object @@ -31,8 +29,7 @@ properties: group: description: The logical grouping of components of a service. type: string - examples: - - app-stack + example: app-stack links: description: A list of links to add to the event. type: array diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_closeincident.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_closeincident.yaml index a53c4f90b226e1..82f9a97a604120 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_closeincident.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_closeincident.yaml @@ -22,13 +22,15 @@ properties: - required: [externalId] properties: correlation_id: - type: ['null', string] + type: string + nullable: true description: > An identifier that is assigned to the incident when it is created by the connector. NOTE: If you use the default value and the rule generates multiple alerts that use the same alert IDs, the latest open incident for this correlation ID is closed unless you specify the external ID. maxLength: 100 default: '{{rule.id}}:{{alert.id}}' externalId: - type: ['null', string] + type: string + nullable: true description: The unique identifier (`incidentId`) for the incident in ServiceNow. \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_createalert.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_createalert.yaml index a53560951361f0..e739a9ed6c91d6 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_createalert.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_createalert.yaml @@ -30,8 +30,7 @@ properties: type: object description: The custom properties of the alert. additionalProperties: true - examples: - - {"key1":"value1","key2":"value2"} + example: {"key1":"value1","key2":"value2"} entity: type: string description: The domain of the alert. For example, the application or server name. diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_fieldsbyissuetype.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_fieldsbyissuetype.yaml index 6c39957c29fc41..e8c8869e7d68b0 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_fieldsbyissuetype.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_fieldsbyissuetype.yaml @@ -18,6 +18,5 @@ properties: id: type: string description: The Jira issue type identifier. - examples: - - 10024 + example: 10024 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_getincident.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_getincident.yaml index 7a16f3d9f8295f..666c0257f68b86 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_getincident.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_getincident.yaml @@ -18,5 +18,4 @@ properties: externalId: type: string description: The Jira, ServiceNow ITSM, or ServiceNow SecOps issue identifier. - examples: - - 71778 + example: 71778 diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_issue.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_issue.yaml index 3743e7fa90bd32..56ee923b40063f 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_issue.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/run_connector_subaction_issue.yaml @@ -17,5 +17,4 @@ properties: id: type: string description: The Jira issue identifier. - examples: - - 71778 \ No newline at end of file + example: 71778 \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_cases_webhook.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_cases_webhook.yaml index 9201a1b1e1d70d..66250b31a94eb6 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_cases_webhook.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_cases_webhook.yaml @@ -9,7 +9,6 @@ properties: name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_cases_webhook.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_swimlane.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_swimlane.yaml index 771625841a0429..81321351b74ec2 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_swimlane.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/update_connector_request_swimlane.yaml @@ -10,7 +10,6 @@ properties: name: type: string description: The display name for the connector. - examples: - - my-connector + example: my-connector secrets: $ref: 'secrets_properties_swimlane.yaml' \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/entrypoint.yaml b/x-pack/plugins/actions/docs/openapi/entrypoint.yaml index d082d91a2a4e5d..ba61b00c3c7379 100644 --- a/x-pack/plugins/actions/docs/openapi/entrypoint.yaml +++ b/x-pack/plugins/actions/docs/openapi/entrypoint.yaml @@ -1,4 +1,4 @@ -openapi: 3.1.0 +openapi: 3.0.3 info: title: Connectors description: OpenAPI schema for Connectors endpoints @@ -14,16 +14,6 @@ tags: servers: - url: / paths: - '/api/actions/connector': - $ref: 'paths/api@actions@connector.yaml' - '/api/actions/connector/{connectorId}': - $ref: 'paths/api@actions@connector@{connectorid}.yaml' - '/api/actions/connector/{connectorId}/_execute': - $ref: paths/api@actions@connector@{connectorid}@_execute.yaml - '/api/actions/connectors': - $ref: paths/api@actions@connectors.yaml - '/api/actions/connector_types': - $ref: paths/api@actions@connector_types.yaml '/s/{spaceId}/api/actions/connector': $ref: 'paths/s@{spaceid}@api@actions@connector.yaml' '/s/{spaceId}/api/actions/connector/{connectorId}': @@ -34,6 +24,17 @@ paths: $ref: paths/s@{spaceid}@api@actions@connector_types.yaml '/s/{spaceId}/api/actions/connector/{connectorId}/_execute': $ref: paths/s@{spaceid}@api@actions@connector@{connectorid}@_execute.yaml +# Default space + '/api/actions/connector': + $ref: 'paths/api@actions@connector.yaml' + '/api/actions/connector/{connectorId}': + $ref: 'paths/api@actions@connector@{connectorid}.yaml' + '/api/actions/connector/{connectorId}/_execute': + $ref: paths/api@actions@connector@{connectorid}@_execute.yaml + '/api/actions/connectors': + $ref: paths/api@actions@connectors.yaml + '/api/actions/connector_types': + $ref: paths/api@actions@connector_types.yaml # Deprecated endpoints: '/s/{spaceId}/api/actions/action/{actionId}': $ref: 'paths/s@{spaceid}@api@actions@action@{actionid}.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/entrypoint_serverless.yaml b/x-pack/plugins/actions/docs/openapi/entrypoint_serverless.yaml index 4780a65da65207..60cca6f18bc440 100644 --- a/x-pack/plugins/actions/docs/openapi/entrypoint_serverless.yaml +++ b/x-pack/plugins/actions/docs/openapi/entrypoint_serverless.yaml @@ -1,4 +1,4 @@ -openapi: 3.1.0 +openapi: 3.0.3 info: title: Connectors description: OpenAPI schema for connectors in Serverless projects @@ -31,6 +31,9 @@ components: type: apiKey in: header name: Authorization - description: 'e.g. Authorization: ApiKey base64AccessApiKey' + description: > + Serverless APIs support only key-based authentication. + You must create an API key and use the encoded value in the request header. + For example: 'Authorization: ApiKey base64AccessApiKey'. security: - apiKeyAuth: [] diff --git a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector.yaml b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector.yaml index c6634bb6ea5326..5f82202bed5345 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector.yaml @@ -1,5 +1,5 @@ post: - summary: Creates a connector. + summary: Create a connector operationId: createConnector tags: - connectors diff --git a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}.yaml b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}.yaml index 6464b9592436a6..c9b4c269e6cc25 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}.yaml @@ -1,5 +1,5 @@ get: - summary: Retrieves a connector by ID. + summary: Get a connector information operationId: getConnector tags: - connectors @@ -21,7 +21,7 @@ get: $ref: '../components/responses/404.yaml' delete: - summary: Deletes a connector. + summary: Delete a connector operationId: deleteConnector tags: - connectors @@ -37,7 +37,7 @@ delete: $ref: '../components/responses/404.yaml' post: - summary: Creates a connector. + summary: Create a connector operationId: createConnectorId tags: - connectors @@ -51,8 +51,7 @@ post: required: true schema: type: string - examples: - - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: @@ -76,7 +75,7 @@ post: $ref: '../components/responses/401.yaml' put: - summary: Updates the attributes for a connector. + summary: Update a connector operationId: updateConnector tags: - connectors diff --git a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}@_execute.yaml b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}@_execute.yaml index 6d4de54cda3bc5..93037c6d217791 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}@_execute.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector@{connectorid}@_execute.yaml @@ -1,5 +1,5 @@ post: - summary: Runs a connector. + summary: Run a connector operationId: runConnector description: > You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. diff --git a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector_types.yaml b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector_types.yaml index 94dbb727eea4a2..3284d79cd9a49d 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector_types.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connector_types.yaml @@ -1,5 +1,5 @@ get: - summary: Retrieves a list of all connector types. + summary: Get all connector types operationId: getConnectorTypes tags: - connectors @@ -24,41 +24,34 @@ get: enabled: type: boolean description: Indicates whether the connector type is enabled in Kibana. - examples: - - true + example: true enabled_in_config: type: boolean description: Indicates whether the connector type is enabled in the Kibana configuration file. - examples: - - true + example: true enabled_in_license: type: boolean description: Indicates whether the connector is enabled in the license. - examples: - - true + example: true id: $ref: '../components/schemas/connector_types.yaml' is_system_action_type: type: boolean - examples: - - false + example: false minimum_license_required: type: string description: The license that is required to use the connector type. - examples: - - basic + example: basic name: type: string description: The name of the connector type. - examples: - - Index + example: Index supported_feature_ids: type: array description: The features that are supported by the connector type. items: $ref: '../components/schemas/features.yaml' - examples: - - [alerting, cases, siem] + example: [alerting, cases, siem] examples: getConnectorTypesServerlessResponse: $ref: '../components/examples/get_connector_types_generativeai_response.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connectors.yaml b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connectors.yaml index 82b83651644e71..b94954173e22e9 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/api@actions@connectors.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/api@actions@connectors.yaml @@ -1,5 +1,5 @@ get: - summary: Retrieves all connectors. + summary: Get all connectors operationId: getConnectors tags: - connectors diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions.yaml index aad5ca61ac3bee..94aa1f5c420a19 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions.yaml @@ -1,5 +1,5 @@ get: - summary: Retrieves all connectors. + summary: Get all connectors operationId: legacyGetConnectors deprecated: true description: Deprecated in 7.13.0. Use the get all connectors API instead. @@ -20,7 +20,7 @@ get: $ref: '../components/responses/401.yaml' post: - summary: Creates a connector. + summary: Create a connector operationId: legacyCreateConnector deprecated: true description: Deprecated in 7.13.0. Use the create connector API instead. diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@action@{actionid}.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@action@{actionid}.yaml index dcf7a2759a35ab..f2a5f62516aba7 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@action@{actionid}.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@action@{actionid}.yaml @@ -1,5 +1,5 @@ delete: - summary: Deletes a connector. + summary: Delete a connector operationId: legacyDeleteConnector deprecated: true description: > @@ -18,7 +18,7 @@ delete: $ref: '../components/responses/401.yaml' get: - summary: Retrieves a connector by ID. + summary: Get connector information operationId: legacyGetConnector description: Deprecated in 7.13.0. Use the get connector API instead. deprecated: true @@ -34,7 +34,7 @@ get: $ref: '../components/responses/401.yaml' put: - summary: Updates the attributes for a connector. + summary: Update a connector operationId: legacyUpdateConnector deprecated: true description: Deprecated in 7.13.0. Use the update connector API instead. diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@action@{actionid}@_execute.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@action@{actionid}@_execute.yaml index 9fe5cedda84de4..1d1db3f341e522 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@action@{actionid}@_execute.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@action@{actionid}@_execute.yaml @@ -1,5 +1,5 @@ post: - summary: Runs a connector. + summary: Run a connector operationId: legacyRunConnector deprecated: true description: Deprecated in 7.13.0. Use the run connector API instead. diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml index f116a699ed8684..749647e8b9ce56 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml @@ -1,5 +1,5 @@ post: - summary: Creates a connector. + summary: Create a connector operationId: createConnectorWithSpaceId description: > You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml index 27351f0954eee6..d4511a486c0e13 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml @@ -1,5 +1,5 @@ get: - summary: Retrieves a connector by ID. + summary: Get connector information operationId: getConnectorWithSpaceId description: > You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. @@ -24,7 +24,7 @@ get: $ref: '../components/responses/404.yaml' delete: - summary: Deletes a connector. + summary: Delete a connector operationId: deleteConnectorWithSpaceId description: > You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. @@ -44,7 +44,7 @@ delete: $ref: '../components/responses/404.yaml' post: - summary: Creates a connector. + summary: Create a connector operationId: createConnectorIdWithSpaceId description: > You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. @@ -59,8 +59,7 @@ post: required: true schema: type: string - examples: - - ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 requestBody: required: true content: @@ -84,7 +83,7 @@ post: $ref: '../components/responses/401.yaml' put: - summary: Updates the attributes for a connector. + summary: Update a connector operationId: updateConnectorWithSpaceId description: > You must have `all` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}@_execute.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}@_execute.yaml index 507194f31c380a..76a30f54bab80a 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}@_execute.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}@_execute.yaml @@ -1,5 +1,5 @@ post: - summary: Runs a connector. + summary: Run a connector operationId: runConnectorWithSpaceId description: > You can use this API to test an action that involves interaction with Kibana services or integrations with third-party systems. diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector_types.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector_types.yaml index 9a0fababdf166e..88fbc1612e5078 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector_types.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector_types.yaml @@ -1,5 +1,5 @@ get: - summary: Retrieves a list of all connector types. + summary: Get all connector types operationId: getConnectorTypesWithSpaceId description: > You do not need any Kibana feature privileges to run this API. @@ -27,37 +27,31 @@ get: enabled: type: boolean description: Indicates whether the connector type is enabled in Kibana. - examples: - - true + example: true enabled_in_config: type: boolean description: Indicates whether the connector type is enabled in the Kibana `.yml` file. - examples: - - true + example: true enabled_in_license: type: boolean description: Indicates whether the connector is enabled in the license. - examples: - - true + example: true id: $ref: '../components/schemas/connector_types.yaml' minimum_license_required: type: string description: The license that is required to use the connector type. - examples: - - basic + example: basic name: type: string description: The name of the connector type. - examples: - - Index + example: Index supported_feature_ids: type: array description: The Kibana features that are supported by the connector type. items: $ref: '../components/schemas/features.yaml' - examples: - - [alerting, uptime, siem] + example: [alerting, uptime, siem] examples: getConnectorTypesResponse: $ref: '../components/examples/get_connector_types_response.yaml' diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connectors.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connectors.yaml index 7670187845710a..3913919998e985 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connectors.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connectors.yaml @@ -1,5 +1,5 @@ get: - summary: Retrieves all connectors. + summary: Get all connectors operationId: getConnectorsWithSpaceId description: > You must have `read` privileges for the **Actions and Connectors** feature in the **Management** section of the Kibana feature privileges. diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@list_action_types.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@list_action_types.yaml index 6bc2b9e5e53a8a..daea4ed5219ebe 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@list_action_types.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@list_action_types.yaml @@ -1,5 +1,5 @@ get: - summary: Retrieves a list of all connector types. + summary: Get connector types operationId: legacyGetConnectorTypes deprecated: true description: Deprecated in 7.13.0. Use the get all connector types API instead. @@ -28,8 +28,7 @@ get: enabledInLicense: type: boolean description: Indicates whether the connector is enabled in the license. - examples: - - true + example: true id: type: string description: The unique identifier for the connector type. From 74903c349c03e610892636fe055eae51ab34b35e Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:56:22 -0400 Subject: [PATCH 055/123] [Security Solution][Endpoint] Fix automated response actions so that they only execute on alerts generated by `agent.type` of `endpoint` (#186333) ## Summary Fixes Automated Response actions so that they are only executed on alerts generated from Elastic Defend. For a background as to why this fix was needed, [see this comment here](https://github.com/elastic/kibana/issues/180774#issuecomment-2139526239). --- ...dule_notification_response_actions.test.ts | 24 +++++++++++++++++-- .../schedule_notification_response_actions.ts | 14 ++++++++--- .../rule_response_actions/types.ts | 1 + 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts index 6fac2725754d5b..4dccc9ad0aae70 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.test.ts @@ -14,7 +14,7 @@ import { responseActionsClientMock } from '../../../endpoint/services/actions/cl describe('ScheduleNotificationResponseActions', () => { const signalOne = { - agent: { id: 'agent-id-1' }, + agent: { id: 'agent-id-1', type: 'endpoint' }, _id: 'alert-id-1', user: { id: 'S-1-5-20' }, process: { @@ -23,7 +23,7 @@ describe('ScheduleNotificationResponseActions', () => { [ALERT_RULE_UUID]: 'rule-id-1', [ALERT_RULE_NAME]: 'rule-name-1', }; - const signalTwo = { agent: { id: 'agent-id-2' }, _id: 'alert-id-2' }; + const signalTwo = { agent: { id: 'agent-id-2', type: 'endpoint' }, _id: 'alert-id-2' }; const getSignals = () => [signalOne, signalTwo]; const osqueryActionMock = { @@ -210,5 +210,25 @@ describe('ScheduleNotificationResponseActions', () => { } ); }); + + it('should only attempt to send response actions to alerts from endpoint', async () => { + const signals = getSignals(); + signals.push({ agent: { id: '123-432', type: 'filebeat' }, _id: '1' }); + const responseActions: RuleResponseAction[] = [ + { + actionTypeId: ResponseActionTypesEnum['.endpoint'], + params: { + command: 'isolate', + comment: 'test process comment', + }, + }, + ]; + await scheduleNotificationResponseActions({ + signals, + responseActions, + }); + + expect(mockedResponseActionsClient.isolate).toHaveBeenCalledTimes(signals.length - 1); + }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts index d20995291b5f17..2fcf09d6cfbb4c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/schedule_notification_response_actions.ts @@ -37,9 +37,17 @@ export const getScheduleNotificationResponseActionsService = }); } if (responseAction.actionTypeId === ResponseActionTypesEnum['.endpoint']) { - await endpointResponseAction(responseAction, endpointAppContextService, { - alerts, - }); + // We currently support only automated response actions for Elastic Defend. This will + // need to be updated once we introduce support for other EDR systems. + // For an explanation of why this is needed, see this comment here: + // https://github.com/elastic/kibana/issues/180774#issuecomment-2139526239 + const alertsFromElasticDefend = alerts.filter((alert) => alert.agent.type === 'endpoint'); + + if (alertsFromElasticDefend.length > 0) { + await endpointResponseAction(responseAction, endpointAppContextService, { + alerts: alertsFromElasticDefend, + }); + } } }) ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts index d34d2eba9e5ab9..e7317acfd7ca1d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions/types.ts @@ -24,6 +24,7 @@ export type Alert = ParsedTechnicalFields & { export interface AlertAgent { id: string; name: string; + type: string; } export interface AlertWithAgent extends Alert { From 793d96ee00fd5c229286d60d292cdd277e322ef4 Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Tue, 18 Jun 2024 20:58:27 +0200 Subject: [PATCH 056/123] [Rule Management] Skip Cypress tests on MKI executions (#186122) ## Summary The `x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/backfill_group.cy.ts` test is failing on MKI environments (the periodic pipeline). This is because the test in order to work need to have a feature flag enabled. FF are not currently supported on MKI environments, that is why in this PR we are skipping it from MKI environments by adding `@skipInServerlessMKI` label to it. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../rule_management/rule_details/backfill_group.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/backfill_group.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/backfill_group.cy.ts index 1b2cbd9add957e..7413b8a8f02c71 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/backfill_group.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_details/backfill_group.cy.ts @@ -34,7 +34,7 @@ import { describe( 'Backfill groups', { - tags: ['@ess', '@serverless'], + tags: ['@ess', '@serverless', '@skipInServerlessMKI'], env: { ftrConfig: { kbnServerArgs: [ From f93f04a4ede23cebc90c36274443caa7945968f8 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 18 Jun 2024 15:39:31 -0400 Subject: [PATCH 057/123] [Fleet] Make enrollment settings API space aware (#186322) --- .../common/types/models/package_policy.ts | 1 + .../fleet/common/types/rest_spec/settings.ts | 1 + .../enrollment_settings_handler.test.ts | 3 + .../settings/enrollment_settings_handler.ts | 11 +- .../fleet/server/routes/setup/handlers.ts | 3 +- .../fleet/server/services/agent_policy.ts | 15 +- .../services/fleet_server/index.test.ts | 13 +- .../server/services/fleet_server/index.ts | 33 ++-- .../fleet/server/services/package_policy.ts | 4 +- .../server/services/package_policy_service.ts | 2 +- .../apis/space_awareness/api_helper.ts | 34 ++++ .../space_awareness/enrollment_settings.ts | 161 ++++++++++++++++++ .../apis/space_awareness/index.js | 1 + 13 files changed, 257 insertions(+), 25 deletions(-) create mode 100644 x-pack/test/fleet_api_integration/apis/space_awareness/enrollment_settings.ts diff --git a/x-pack/plugins/fleet/common/types/models/package_policy.ts b/x-pack/plugins/fleet/common/types/models/package_policy.ts index c50c06b890ea14..1b8a407ff8dd92 100644 --- a/x-pack/plugins/fleet/common/types/models/package_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/package_policy.ts @@ -99,6 +99,7 @@ export interface UpdatePackagePolicy extends NewPackagePolicy { // SO definition for this type is declared in server/types/interfaces export interface PackagePolicy extends Omit { id: string; + spaceId?: string; inputs: PackagePolicyInput[]; version?: string; agents?: number; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/settings.ts b/x-pack/plugins/fleet/common/types/rest_spec/settings.ts index 33abccbc88e74d..73ad6a3a219fce 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/settings.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/settings.ts @@ -34,6 +34,7 @@ export type EnrollmentSettingsFleetServerPolicy = Pick< | 'has_fleet_server' | 'fleet_server_host_id' | 'download_source_id' + | 'space_id' >; export interface GetEnrollmentSettingsResponse { diff --git a/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.test.ts b/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.test.ts index b41debffb3e6be..0a39101db84819 100644 --- a/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.test.ts +++ b/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.test.ts @@ -16,6 +16,9 @@ jest.mock('../../services', () => ({ get: jest.fn(), getByIDs: jest.fn(), }, + appContextService: { + getInternalUserSOClientWithoutSpaceExtension: jest.fn(), + }, downloadSourceService: { list: jest.fn().mockResolvedValue({ items: [ diff --git a/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.ts b/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.ts index 1662fed3fc31b6..132777867becbf 100644 --- a/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.ts +++ b/x-pack/plugins/fleet/server/routes/settings/enrollment_settings_handler.ts @@ -18,7 +18,7 @@ import type { } from '../../../common/types'; import type { FleetRequestHandler, GetEnrollmentSettingsRequestSchema } from '../../types'; import { defaultFleetErrorHandler } from '../../errors'; -import { agentPolicyService, downloadSourceService } from '../../services'; +import { agentPolicyService, appContextService, downloadSourceService } from '../../services'; import { getFleetServerHostsForAgentPolicy } from '../../services/fleet_server_host'; import { getFleetProxy } from '../../services/fleet_proxies'; import { getFleetServerPolicies, hasFleetServersForPolicies } from '../../services/fleet_server'; @@ -53,8 +53,8 @@ export const getEnrollmentSettingsHandler: FleetRequestHandler< settingsResponse.fleet_server.policies = fleetServerPolicies; settingsResponse.fleet_server.has_active = await hasFleetServersForPolicies( esClient, - soClient, - fleetServerPolicies.map((p) => p.id), + appContextService.getInternalUserSOClientWithoutSpaceExtension(), + fleetServerPolicies, true ); } @@ -115,6 +115,7 @@ export const getFleetServerOrAgentPolicies = async ( has_fleet_server: policy.has_fleet_server, fleet_server_host_id: policy.fleet_server_host_id, download_source_id: policy.download_source_id, + space_id: policy.space_id, }); // If an agent policy is specified, return only that policy @@ -136,7 +137,9 @@ export const getFleetServerOrAgentPolicies = async ( } // If an agent policy is not specified, return all fleet server policies - const fleetServerPolicies = (await getFleetServerPolicies(soClient)).map(mapPolicy); + const fleetServerPolicies = ( + await getFleetServerPolicies(appContextService.getInternalUserSOClientWithoutSpaceExtension()) + ).map(mapPolicy); return { fleetServerPolicies }; }; diff --git a/x-pack/plugins/fleet/server/routes/setup/handlers.ts b/x-pack/plugins/fleet/server/routes/setup/handlers.ts index 58555f233142a4..019fb2af5276b8 100644 --- a/x-pack/plugins/fleet/server/routes/setup/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/setup/handlers.ts @@ -16,10 +16,9 @@ import { isSecretStorageEnabled } from '../../services/secrets'; export const getFleetStatusHandler: FleetRequestHandler = async (context, request, response) => { const coreContext = await context.core; - const fleetContext = await context.fleet; const esClient = coreContext.elasticsearch.client.asInternalUser; - const soClient = fleetContext.internalSoClient; + const soClient = appContextService.getInternalUserSOClientWithoutSpaceExtension(); try { const isApiKeysEnabled = await appContextService diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index d3d94fa581955f..029352e145ca6f 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -414,10 +414,20 @@ class AgentPolicyService { public async getByIDs( soClient: SavedObjectsClientContract, - ids: string[], + ids: Array, options: { fields?: string[]; withPackagePolicies?: boolean; ignoreMissing?: boolean } = {} ): Promise { - const objects = ids.map((id) => ({ ...options, id, type: SAVED_OBJECT_TYPE })); + const objects = ids.map((id) => { + if (typeof id === 'string') { + return { ...options, id, type: SAVED_OBJECT_TYPE }; + } + return { + ...options, + id: id.id, + namespaces: id.spaceId ? [id.spaceId] : undefined, + type: SAVED_OBJECT_TYPE, + }; + }); const bulkGetResponse = await soClient.bulkGet(objects); const agentPolicies = await pMap( @@ -432,7 +442,6 @@ class AgentPolicyService { throw new FleetError(agentPolicySO.error.message); } } - const agentPolicy = mapAgentPolicySavedObjectToAgentPolicy(agentPolicySO); if (options.withPackagePolicies) { const agentPolicyWithPackagePolicies = await this.get( diff --git a/x-pack/plugins/fleet/server/services/fleet_server/index.test.ts b/x-pack/plugins/fleet/server/services/fleet_server/index.test.ts index 0a4ce315043835..f00d78cd59ad96 100644 --- a/x-pack/plugins/fleet/server/services/fleet_server/index.test.ts +++ b/x-pack/plugins/fleet/server/services/fleet_server/index.test.ts @@ -130,6 +130,7 @@ describe('getFleetServerPolicies', () => { version: '1.0.0', }, policy_id: 'fs-policy-1', + policy_ids: ['fs-policy-1'], }, { id: 'package-policy-2', @@ -140,6 +141,7 @@ describe('getFleetServerPolicies', () => { version: '1.0.0', }, policy_id: 'fs-policy-2', + policy_ids: ['fs-policy-2'], }, { id: 'package-policy-3', @@ -150,6 +152,7 @@ describe('getFleetServerPolicies', () => { version: '1.0.0', }, policy_id: 'agent-policy-2', + policy_ids: ['agent-policy-2'], }, ]; const mockFleetServerPolicies = [ @@ -218,7 +221,7 @@ describe('hasActiveFleetServersForPolicies', () => { const hasFs = await hasFleetServersForPolicies( mockEsClient, mockSoClient, - ['policy-1'], + [{ id: 'policy-1' }], true ); expect(hasFs).toBe(true); @@ -241,7 +244,7 @@ describe('hasActiveFleetServersForPolicies', () => { const hasFs = await hasFleetServersForPolicies( mockEsClient, mockSoClient, - ['policy-1'], + [{ id: 'policy-1' }], true ); expect(hasFs).toBe(true); @@ -264,7 +267,7 @@ describe('hasActiveFleetServersForPolicies', () => { const hasFs = await hasFleetServersForPolicies( mockEsClient, mockSoClient, - ['policy-1'], + [{ id: 'policy-1' }], true ); expect(hasFs).toBe(false); @@ -286,7 +289,9 @@ describe('hasActiveFleetServersForPolicies', () => { online: 0, error: 0, }); - const hasFs = await hasFleetServersForPolicies(mockEsClient, mockSoClient, ['policy-1']); + const hasFs = await hasFleetServersForPolicies(mockEsClient, mockSoClient, [ + { id: 'policy-1' }, + ]); expect(hasFs).toBe(true); }); }); diff --git a/x-pack/plugins/fleet/server/services/fleet_server/index.ts b/x-pack/plugins/fleet/server/services/fleet_server/index.ts index 88ba7ccc710d50..004a0deeea7b7f 100644 --- a/x-pack/plugins/fleet/server/services/fleet_server/index.ts +++ b/x-pack/plugins/fleet/server/services/fleet_server/index.ts @@ -6,15 +6,15 @@ */ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; import semverGte from 'semver/functions/gte'; import semverCoerce from 'semver/functions/coerce'; +import { uniqBy } from 'lodash'; import type { AgentPolicy } from '../../../common/types'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, FLEET_SERVER_PACKAGE } from '../../../common/constants'; - import { SO_SEARCH_LIMIT } from '../../constants'; import { getAgentsByKuery, getAgentStatusById } from '../agents'; - import { packagePolicyService } from '../package_policy'; import { agentPolicyService } from '../agent_policy'; import { getAgentStatusForAgentPolicy } from '../agents'; @@ -28,16 +28,20 @@ export const getFleetServerPolicies = async ( ): Promise => { const fleetServerPackagePolicies = await packagePolicyService.list(soClient, { kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${FLEET_SERVER_PACKAGE}`, + spaceId: '*', }); // Extract associated fleet server agent policy IDs - const fleetServerAgentPolicyIds = [ - ...new Set(fleetServerPackagePolicies.items.flatMap((p) => p.policy_ids)), - ]; + const fleetServerAgentPolicyIds = fleetServerPackagePolicies.items.flatMap((p) => + p.policy_ids?.map((id) => ({ id, spaceId: p.spaceId } ?? [])) + ); // Retrieve associated agent policies const fleetServerAgentPolicies = fleetServerAgentPolicyIds.length - ? await agentPolicyService.getByIDs(soClient, fleetServerAgentPolicyIds) + ? await agentPolicyService.getByIDs( + soClient, + uniqBy(fleetServerAgentPolicyIds, (p) => `${p?.spaceId ?? ''}:${p.id}`) + ) : []; return fleetServerAgentPolicies; @@ -51,15 +55,24 @@ export const getFleetServerPolicies = async ( export const hasFleetServersForPolicies = async ( esClient: ElasticsearchClient, soClient: SavedObjectsClientContract, - agentPolicyIds: string[], + agentPolicies: Array>, activeOnly: boolean = false ): Promise => { - if (agentPolicyIds.length > 0) { + if (agentPolicies.length > 0) { const agentStatusesRes = await getAgentStatusForAgentPolicy( esClient, soClient, undefined, - agentPolicyIds.map((id) => `policy_id:${id}`).join(' or ') + agentPolicies + .map(({ id, space_id: spaceId }) => { + const space = + spaceId && spaceId !== DEFAULT_SPACE_ID + ? `namespaces:"${spaceId}"` + : `not namespaces:* or namespaces:"${DEFAULT_SPACE_ID}"`; + + return `(policy_id:${id} and (${space}))`; + }) + .join(' or ') ); return activeOnly @@ -79,7 +92,7 @@ export async function hasFleetServers( return await hasFleetServersForPolicies( esClient, soClient, - (await getFleetServerPolicies(soClient)).map((policy) => policy.id) + await getFleetServerPolicies(soClient) ); } diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index cae84f2c8f5b16..dd4d26e28ca7e7 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -726,7 +726,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { public async list( soClient: SavedObjectsClientContract, - options: ListWithKuery + options: ListWithKuery & { spaceId?: string } ): Promise> { const { page = 1, perPage = 20, sortField = 'updated_at', sortOrder = 'desc', kuery } = options; @@ -737,6 +737,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { page, perPage, filter: kuery ? normalizeKuery(SAVED_OBJECT_TYPE, kuery) : undefined, + namespaces: options.spaceId ? [options.spaceId] : undefined, }); for (const packagePolicy of packagePolicies?.saved_objects ?? []) { @@ -752,6 +753,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { id: packagePolicySO.id, version: packagePolicySO.version, ...packagePolicySO.attributes, + spaceId: packagePolicySO.namespaces?.[0], })), total: packagePolicies?.total, page, diff --git a/x-pack/plugins/fleet/server/services/package_policy_service.ts b/x-pack/plugins/fleet/server/services/package_policy_service.ts index 56e68537afb7e6..5f5e775bf910a9 100644 --- a/x-pack/plugins/fleet/server/services/package_policy_service.ts +++ b/x-pack/plugins/fleet/server/services/package_policy_service.ts @@ -105,7 +105,7 @@ export interface PackagePolicyClient { list( soClient: SavedObjectsClientContract, - options: ListWithKuery + options: ListWithKuery & { spaceId?: string } ): Promise>; listIds( diff --git a/x-pack/test/fleet_api_integration/apis/space_awareness/api_helper.ts b/x-pack/test/fleet_api_integration/apis/space_awareness/api_helper.ts index cff3d3ddb637b5..4b166d040625b9 100644 --- a/x-pack/test/fleet_api_integration/apis/space_awareness/api_helper.ts +++ b/x-pack/test/fleet_api_integration/apis/space_awareness/api_helper.ts @@ -19,6 +19,7 @@ import { GetOneEnrollmentAPIKeyResponse, PostEnrollmentAPIKeyResponse, PostEnrollmentAPIKeyRequest, + GetEnrollmentSettingsResponse, } from '@kbn/fleet-plugin/common/types'; import { GetUninstallTokenResponse, @@ -30,6 +31,15 @@ export class SpaceTestApiClient { private getBaseUrl(spaceId?: string) { return spaceId ? `/s/${spaceId}` : ''; } + async setup(spaceId?: string): Promise { + const { body: res } = await this.supertest + .post(`${this.getBaseUrl(spaceId)}/api/fleet/setup`) + .set('kbn-xsrf', 'xxxx') + .send({}) + .expect(200); + + return res; + } // Agent policies async createAgentPolicy(spaceId?: string): Promise { const { body: res } = await this.supertest @@ -45,6 +55,22 @@ export class SpaceTestApiClient { return res; } + async createFleetServerPolicy(spaceId?: string): Promise { + const { body: res } = await this.supertest + .post(`${this.getBaseUrl(spaceId)}/api/fleet/agent_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: `test ${uuidV4()}`, + description: '', + namespace: 'default', + inactivity_timeout: 24 * 1000, + has_fleet_server: true, + force: true, + }) + .expect(200); + + return res; + } async deleteAgentPolicy(agentPolicyId: string, spaceId?: string) { await this.supertest .post(`${this.getBaseUrl(spaceId)}/api/fleet/agent_policies/delete`) @@ -139,4 +165,12 @@ export class SpaceTestApiClient { return res; } + // Enrollment Settings + async getEnrollmentSettings(spaceId?: string): Promise { + const { body: res } = await this.supertest + .get(`${this.getBaseUrl(spaceId)}/internal/fleet/settings/enrollment`) + .expect(200); + + return res; + } } diff --git a/x-pack/test/fleet_api_integration/apis/space_awareness/enrollment_settings.ts b/x-pack/test/fleet_api_integration/apis/space_awareness/enrollment_settings.ts new file mode 100644 index 00000000000000..d5eb41afb21042 --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/space_awareness/enrollment_settings.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 { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; +import { skipIfNoDockerRegistry } from '../../helpers'; +import { SpaceTestApiClient } from './api_helper'; +import { cleanFleetIndices } from './helpers'; +import { setupTestSpaces, TEST_SPACE_1 } from './space_helpers'; + +export default function (providerContext: FtrProviderContext) { + const { getService } = providerContext; + const supertest = getService('supertest'); + const esClient = getService('es'); + const kibanaServer = getService('kibanaServer'); + const createFleetAgent = async (agentPolicyId: string, spaceId?: string) => { + const agentResponse = await esClient.index({ + index: '.fleet-agents', + refresh: true, + body: { + access_api_key_id: 'api-key-3', + active: true, + policy_id: agentPolicyId, + policy_revision_idx: 1, + last_checkin_status: 'online', + type: 'PERMANENT', + local_metadata: { + host: { hostname: 'host123' }, + elastic: { agent: { version: '8.15.0' } }, + }, + user_provided_metadata: {}, + enrolled_at: new Date().toISOString(), + last_checkin: new Date().toISOString(), + tags: ['tag1'], + namespaces: spaceId ? [spaceId] : undefined, + }, + }); + + return agentResponse._id; + }; + describe('enrollment_settings', async function () { + skipIfNoDockerRegistry(providerContext); + const apiClient = new SpaceTestApiClient(supertest); + + describe('Without Fleet server setup', () => { + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.savedObjects.cleanStandardList({ + space: TEST_SPACE_1, + }); + await cleanFleetIndices(esClient); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.savedObjects.cleanStandardList({ + space: TEST_SPACE_1, + }); + await cleanFleetIndices(esClient); + }); + + setupTestSpaces(providerContext); + + before(async () => { + await apiClient.setup(); + }); + + describe('GET /enrollments/settings', () => { + it('in default space it should not return an active fleet server', async () => { + const res = await apiClient.getEnrollmentSettings(); + expect(res.fleet_server.has_active).to.be(false); + }); + + it('in a specific spaceit should not return an active fleet server', async () => { + const res = await apiClient.getEnrollmentSettings(TEST_SPACE_1); + expect(res.fleet_server.has_active).to.be(false); + }); + }); + }); + + describe('With Fleet server setup in a specific space', () => { + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.savedObjects.cleanStandardList({ + space: TEST_SPACE_1, + }); + await cleanFleetIndices(esClient); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.savedObjects.cleanStandardList({ + space: TEST_SPACE_1, + }); + await cleanFleetIndices(esClient); + }); + + setupTestSpaces(providerContext); + + before(async () => { + await apiClient.setup(); + const testSpaceFleetServerPolicy = await apiClient.createFleetServerPolicy(TEST_SPACE_1); + await createFleetAgent(testSpaceFleetServerPolicy.item.id, TEST_SPACE_1); + }); + + describe('GET /enrollments/settings', () => { + it('in default space it should return all policies and active fleet server', async () => { + const res = await apiClient.getEnrollmentSettings(); + expect(res.fleet_server.has_active).to.be(true); + }); + + it('in a specific space it should return all policies and active fleet server', async () => { + const res = await apiClient.getEnrollmentSettings(TEST_SPACE_1); + expect(res.fleet_server.has_active).to.be(true); + }); + }); + }); + + describe('With Fleet server setup in default space', () => { + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.savedObjects.cleanStandardList({ + space: TEST_SPACE_1, + }); + await cleanFleetIndices(esClient); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.savedObjects.cleanStandardList({ + space: TEST_SPACE_1, + }); + await cleanFleetIndices(esClient); + }); + + setupTestSpaces(providerContext); + + before(async () => { + await apiClient.setup(); + const defaultFleetServerPolicy = await apiClient.createFleetServerPolicy(); + await createFleetAgent(defaultFleetServerPolicy.item.id); + }); + + describe('GET /enrollments/settings', () => { + it('in default space it should return all policies and active fleet server', async () => { + const res = await apiClient.getEnrollmentSettings(); + expect(res.fleet_server.has_active).to.be(true); + }); + + it('in a specific space it should return all policies and active fleet server', async () => { + const res = await apiClient.getEnrollmentSettings(TEST_SPACE_1); + expect(res.fleet_server.has_active).to.be(true); + }); + }); + }); + }); +} diff --git a/x-pack/test/fleet_api_integration/apis/space_awareness/index.js b/x-pack/test/fleet_api_integration/apis/space_awareness/index.js index 4313c329104f21..3a3d9ea9071507 100644 --- a/x-pack/test/fleet_api_integration/apis/space_awareness/index.js +++ b/x-pack/test/fleet_api_integration/apis/space_awareness/index.js @@ -11,5 +11,6 @@ export default function loadTests({ loadTestFile }) { loadTestFile(require.resolve('./uninstall_tokens')); loadTestFile(require.resolve('./agent_policies')); loadTestFile(require.resolve('./agents')); + loadTestFile(require.resolve('./enrollment_settings')); }); } From a455012d704f31efd81bfadca4d7333a53032582 Mon Sep 17 00:00:00 2001 From: Bharat Pasupula <123897612+bhapas@users.noreply.github.com> Date: Tue, 18 Jun 2024 21:53:17 +0200 Subject: [PATCH 058/123] [Security GenAI][Integration Assistant] Create OpenAPI spec for Integration Assistant APIs (#186085) --- .../build_integration.schema.yaml | 33 ++++ .../build_integration/build_integration.ts | 16 ++ .../categorization_route.schema.yaml | 43 +++++ .../categorization/categorization_route.ts | 30 ++++ .../check_pipeline/check_pipeline.schema.yaml | 34 ++++ .../api/check_pipeline/check_pipeline.ts | 21 +++ .../common/api/ecs/ecs_route.schema.yaml | 42 +++++ .../common/api/ecs/ecs_route.ts | 30 ++++ .../api/model/common_attributes.schema.yaml | 156 ++++++++++++++++ .../common/api/model/common_attributes.ts | 169 ++++++++++++++++++ .../model/processor_attributes.schema.yaml | 36 ++++ .../common/api/model/processor_attributes.ts | 52 ++++++ .../api/model/response_schemas.schema.yaml | 65 +++++++ .../common/api/model/response_schemas.ts | 49 +++++ .../api/related/related_route.schema.yaml | 43 +++++ .../common/api/related/related_route.ts | 30 ++++ .../integration_assistant/common/index.ts | 41 ++--- .../integration_assistant/common/types.ts | 119 ------------ .../server/graphs/ecs/graph.ts | 14 +- .../server/integration_builder/agent.ts | 6 +- .../integration_builder/build_integration.ts | 4 +- .../server/integration_builder/data_stream.ts | 4 +- .../server/integration_builder/pipeline.ts | 1 + .../server/routes/build_integration_routes.ts | 39 +--- .../server/routes/categorization_routes.ts | 84 ++++----- .../server/routes/ecs_routes.ts | 89 ++++----- .../server/routes/pipeline_routes.ts | 26 +-- .../server/routes/related_routes.ts | 80 ++++----- .../server/util/route_validation.ts | 21 +++ .../integration_assistant/tsconfig.json | 3 +- 30 files changed, 1028 insertions(+), 352 deletions(-) create mode 100644 x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.schema.yaml create mode 100644 x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.ts create mode 100644 x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.schema.yaml create mode 100644 x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.ts create mode 100644 x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.schema.yaml create mode 100644 x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.ts create mode 100644 x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.schema.yaml create mode 100644 x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.ts create mode 100644 x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml create mode 100644 x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts create mode 100644 x-pack/plugins/integration_assistant/common/api/model/processor_attributes.schema.yaml create mode 100644 x-pack/plugins/integration_assistant/common/api/model/processor_attributes.ts create mode 100644 x-pack/plugins/integration_assistant/common/api/model/response_schemas.schema.yaml create mode 100644 x-pack/plugins/integration_assistant/common/api/model/response_schemas.ts create mode 100644 x-pack/plugins/integration_assistant/common/api/related/related_route.schema.yaml create mode 100644 x-pack/plugins/integration_assistant/common/api/related/related_route.ts delete mode 100644 x-pack/plugins/integration_assistant/common/types.ts create mode 100644 x-pack/plugins/integration_assistant/server/util/route_validation.ts diff --git a/x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.schema.yaml b/x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.schema.yaml new file mode 100644 index 00000000000000..798ead34114a6a --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.schema.yaml @@ -0,0 +1,33 @@ +openapi: 3.0.3 +info: + title: Integration Assistatnt Build Integrarion API endpoint + version: "1" +paths: + /api/integration_assistant/build: + post: + summary: Builds Integration with the given input samples + operationId: BuildIntegration + x-codegen-enabled: false + description: Build Integration for the given input samples + tags: + - Build Integration API + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - integration + properties: + integration: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/Integration" + responses: + 200: + description: Indicates a successful call. + content: + application/octet-stream: + schema: + # a binary file of any type + type: string + format: binary diff --git a/x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.ts b/x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.ts new file mode 100644 index 00000000000000..728b6d74036962 --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.ts @@ -0,0 +1,16 @@ +/* + * 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 { z } from 'zod'; + +import { Integration } from '../model/common_attributes'; + +export type BuildIntegrationRequestBody = z.infer; +export const BuildIntegrationRequestBody = z.object({ + integration: Integration, +}); +export type BuildIntegrationRequestBodyInput = z.input; diff --git a/x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.schema.yaml b/x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.schema.yaml new file mode 100644 index 00000000000000..d46213e5c8afba --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.schema.yaml @@ -0,0 +1,43 @@ +openapi: 3.0.3 +info: + title: Integration Assistatnt Categorization API endpoint + version: "1" +paths: + /api/integration_assistant/categorization: + post: + summary: Builds Categorization processors based on the samples + operationId: Categorization + x-codegen-enabled: false + description: Perform Categorization for the given ecs mappings. + tags: + - Categorization API + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - packageName + - datastreamName + - rawSamples + - currentPipeline + - connectorId + properties: + packageName: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/PackageName" + datastreamName: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/DatastreamName" + rawSamples: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/RawSamples" + currentPipeline: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/Pipeline" + connectorId: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/Connector" + responses: + 200: + description: Indicates a successful call. + content: + application/json: + schema: + $ref: "../model/response_schemas.schema.yaml#/components/schemas/CategorizationAPIResponse" diff --git a/x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.ts b/x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.ts new file mode 100644 index 00000000000000..e3c81c95b7404a --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +import { + Connector, + DatastreamName, + PackageName, + Pipeline, + RawSamples, +} from '../model/common_attributes'; +import { CategorizationAPIResponse } from '../model/response_schemas'; + +export type CategorizationRequestBody = z.infer; +export const CategorizationRequestBody = z.object({ + packageName: PackageName, + datastreamName: DatastreamName, + rawSamples: RawSamples, + currentPipeline: Pipeline, + connectorId: Connector, +}); +export type CategorizationRequestBodyInput = z.input; + +export type CategorizationResponse = z.infer; +export const CategorizationResponse = CategorizationAPIResponse; diff --git a/x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.schema.yaml b/x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.schema.yaml new file mode 100644 index 00000000000000..22785fc40bbf2c --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.schema.yaml @@ -0,0 +1,34 @@ +openapi: 3.0.3 +info: + title: Integration Assistatnt Check Pipeline API endpoint + version: "1" +paths: + /api/integration_assistant/pipeline: + post: + summary: Checks if the pipeline is valid for the given samples + operationId: CheckPipeline + x-codegen-enabled: false + description: Check latest pipeline against the input samples. + tags: + - Check Pipeline API + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - rawSamples + - pipeline + properties: + rawSamples: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/RawSamples" + pipeline: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/Pipeline" + responses: + 200: + description: Indicates a successful call. + content: + application/json: + schema: + $ref: "../model/response_schemas.schema.yaml#/components/schemas/CheckPipelineAPIResponse" diff --git a/x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.ts b/x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.ts new file mode 100644 index 00000000000000..39197c3675b214 --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +import { Pipeline, RawSamples } from '../model/common_attributes'; +import { CheckPipelineAPIResponse } from '../model/response_schemas'; + +export type CheckPipelineRequestBody = z.infer; +export const CheckPipelineRequestBody = z.object({ + rawSamples: RawSamples, + pipeline: Pipeline, +}); +export type CheckPipelineRequestBodyInput = z.input; + +export type CheckPipelineResponse = z.infer; +export const CheckPipelineResponse = CheckPipelineAPIResponse; diff --git a/x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.schema.yaml b/x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.schema.yaml new file mode 100644 index 00000000000000..996635404e0b9b --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.schema.yaml @@ -0,0 +1,42 @@ +openapi: 3.0.3 +info: + title: Integration Assistatnt ECS Mapping API endpoint + version: "1" +paths: + /api/integration_assistant/ecs: + post: + summary: Builds ECS Mapping based on the input samples + operationId: EcsMapping + x-codegen-enabled: false + description: Perform ECS mapping for the given input JSON samples + tags: + - ECS Mapping API + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - packageName + - datastreamName + - rawSamples + - connectorId + properties: + packageName: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/PackageName" + datastreamName: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/DatastreamName" + rawSamples: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/RawSamples" + mapping: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/Mapping" + connectorId: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/Connector" + responses: + 200: + description: Indicates a successful call. + content: + application/json: + schema: + $ref: "../model/response_schemas.schema.yaml#/components/schemas/EcsMappingAPIResponse" diff --git a/x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.ts b/x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.ts new file mode 100644 index 00000000000000..0a265c75da4939 --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +import { + Connector, + DatastreamName, + Mapping, + PackageName, + RawSamples, +} from '../model/common_attributes'; +import { EcsMappingAPIResponse } from '../model/response_schemas'; + +export type EcsMappingRequestBody = z.infer; +export const EcsMappingRequestBody = z.object({ + packageName: PackageName, + datastreamName: DatastreamName, + rawSamples: RawSamples, + mapping: Mapping.optional(), + connectorId: Connector, +}); +export type EcsMappingRequestBodyInput = z.input; + +export type EcsMappingResponse = z.infer; +export const EcsMappingResponse = EcsMappingAPIResponse; diff --git a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml new file mode 100644 index 00000000000000..eb8c303edb5abe --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml @@ -0,0 +1,156 @@ +openapi: 3.0.3 +info: + title: Common Rule Attributes + version: "not applicable" +paths: {} +components: + x-codegen-enabled: false + schemas: + PackageName: + type: string + minLength: 1 + description: Package name for the integration to be built. + + DatastreamName: + type: string + minLength: 1 + description: Datastream name for the integration to be built. + + RawSamples: + type: array + items: + type: string + description: String array containing the json raw samples that are used for ecs mapping. + + Mapping: + type: object + description: mapping object to ECS Mapping Request. + + Connector: + type: string + description: LLM Connector to be used in each API request. + + Docs: + type: array + description: An array of processed documents. + items: + type: object + + Pipeline: + type: object + description: The pipeline object. + required: + - processors + properties: + name: + type: string + description: The name of the pipeline. + description: + type: string + description: The description of the pipeline. + version: + type: integer + description: The version of the pipeline. + processors: + type: array + items: + $ref: "../model/processor_attributes.schema.yaml#/components/schemas/ESProcessorItem" + description: The processors to execute. + on_failure: + type: array + items: + $ref: "../model/processor_attributes.schema.yaml#/components/schemas/ESProcessorItem" + description: The processors to execute if the pipeline fails. + + InputType: + type: string + description: The input type for the datastream to pull logs from. + enum: + - aws_cloudwatch + - aws_s3 + - azure_blob_storage + - azure_eventhub + - cloudfoundry + - filestream + - gcp_pubsub + - gcs + - http_endpoint + - journald + - kafka + - tcp + - udp + + Datastream: + type: object + description: The datastream object. + required: + - name + - title + - description + - inputTypes + - rawSamples + - pipeline + - docs + properties: + name: + type: string + description: The name of the datastream. + title: + type: string + description: The title of the datastream. + description: + type: string + description: The description of the datastream. + inputTypes: + type: array + items: + $ref: "#/components/schemas/InputType" + description: The input types of the datastream. + rawSamples: + $ref: "#/components/schemas/RawSamples" + description: The raw samples of the datastream. + pipeline: + $ref: "#/components/schemas/Pipeline" + description: The pipeline of the datastream. + docs: + $ref: "#/components/schemas/Docs" + description: The documents of the datastream. + + Integration: + type: object + description: The integration object. + required: + - name + - title + - description + - dataStreams + properties: + name: + type: string + description: The name of the integration. + title: + type: string + description: The title of the integration. + description: + type: string + description: The description of the integration. + dataStreams: + type: array + items: + $ref: "#/components/schemas/Datastream" + description: The datastreams of the integration. + logo: + type: string + description: The logo of the integration. + + PipelineResults: + type: array + description: An array of pipeline results. + items: + type: object + + Errors: + type: array + description: An array of errors. + items: + type: object diff --git a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts new file mode 100644 index 00000000000000..426224a0622d01 --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts @@ -0,0 +1,169 @@ +/* + * 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 { z } from 'zod'; + +import { ESProcessorItem } from './processor_attributes'; + +/** + * Package name for the integration to be built. + */ +export type PackageName = z.infer; +export const PackageName = z.string().min(1); + +/** + * Datastream name for the integration to be built. + */ +export type DatastreamName = z.infer; +export const DatastreamName = z.string().min(1); + +/** + * String array containing the json raw samples that are used for ecs mapping. + */ +export type RawSamples = z.infer; +export const RawSamples = z.array(z.string()); + +/** + * mapping object to ECS Mapping Request. + */ +export type Mapping = z.infer; +export const Mapping = z.object({}); + +/** + * LLM Connector to be used in each API request. + */ +export type Connector = z.infer; +export const Connector = z.string(); + +/** + * An array of processed documents. + */ +export type Docs = z.infer; +export const Docs = z.array(z.object({})); + +/** + * The pipeline object. + */ +export type Pipeline = z.infer; +export const Pipeline = z.object({ + /** + * The name of the pipeline. + */ + name: z.string().optional(), + /** + * The description of the pipeline. + */ + description: z.string().optional(), + /** + * The version of the pipeline. + */ + version: z.number().int().optional(), + /** + * The processors to execute. + */ + processors: z.array(ESProcessorItem), + /** + * The processors to execute if the pipeline fails. + */ + on_failure: z.array(ESProcessorItem).optional(), +}); + +/** + * The input type for the datastream to pull logs from. + */ +export type InputType = z.infer; +export const InputType = z.enum([ + 'aws_cloudwatch', + 'aws_s3', + 'azure_blob_storage', + 'azure_eventhub', + 'cloudfoundry', + 'filestream', + 'gcp_pubsub', + 'gcs', + 'http_endpoint', + 'journald', + 'kafka', + 'tcp', + 'udp', +]); +export type InputTypeEnum = typeof InputType.enum; +export const InputTypeEnum = InputType.enum; + +/** + * The datastream object. + */ +export type Datastream = z.infer; +export const Datastream = z.object({ + /** + * The name of the datastream. + */ + name: z.string(), + /** + * The title of the datastream. + */ + title: z.string(), + /** + * The description of the datastream. + */ + description: z.string(), + /** + * The input types of the datastream. + */ + inputTypes: z.array(InputType), + /** + * The raw samples of the datastream. + */ + rawSamples: RawSamples, + /** + * The pipeline of the datastream. + */ + pipeline: Pipeline, + /** + * The documents of the datastream. + */ + docs: Docs, +}); + +/** + * The integration object. + */ +export type Integration = z.infer; +export const Integration = z.object({ + /** + * The name of the integration. + */ + name: z.string(), + /** + * The title of the integration. + */ + title: z.string(), + /** + * The description of the integration. + */ + description: z.string(), + /** + * The datastreams of the integration. + */ + dataStreams: z.array(Datastream), + /** + * The logo of the integration. + */ + logo: z.string().optional(), +}); + +/** + * An array of pipeline results. + */ +export type PipelineResults = z.infer; +export const PipelineResults = z.array(z.object({})); + +/** + * An array of errors. + */ +export type Errors = z.infer; +export const Errors = z.array(z.object({})); diff --git a/x-pack/plugins/integration_assistant/common/api/model/processor_attributes.schema.yaml b/x-pack/plugins/integration_assistant/common/api/model/processor_attributes.schema.yaml new file mode 100644 index 00000000000000..a0c930361737a1 --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/model/processor_attributes.schema.yaml @@ -0,0 +1,36 @@ +openapi: 3.0.3 +info: + title: Common Rule Attributes + version: "not applicable" +paths: {} +components: + x-codegen-enabled: false + schemas: + ESProcessorItem: + type: object + description: Processor item for the Elasticsearch processor. + additionalProperties: + $ref: "#/components/schemas/ESProcessorOptions" + + ESProcessorOptions: + type: object + description: Processor options for the Elasticsearch processor. + properties: + on_failure: + type: array + items: + $ref: "#/components/schemas/ESProcessorItem" + description: An array of items to execute if the processor fails. + ignore_failure: + type: boolean + description: If true, the processor continues to the next processor if the current processor fails. + ignore_missing: + type: boolean + description: If true, the processor continues to the next processor if the field is missing. + if: + type: string + description: Conditionally execute the processor. + tag: + type: string + description: A tag to assign to the document after processing. + additionalProperties: true diff --git a/x-pack/plugins/integration_assistant/common/api/model/processor_attributes.ts b/x-pack/plugins/integration_assistant/common/api/model/processor_attributes.ts new file mode 100644 index 00000000000000..a46f04e3fa1307 --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/model/processor_attributes.ts @@ -0,0 +1,52 @@ +/* + * 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 { z } from 'zod'; + +/** + * Processor item for the Elasticsearch processor. + */ +export type ESProcessorItem = Record; +export const ESProcessorItem: z.ZodType = z + .object({}) + .catchall(z.lazy(() => ESProcessorOptions)); + +/** + * Processor options for the Elasticsearch processor. + */ +export interface ESProcessorOptions { + on_failure?: ESProcessorItem[]; + ignore_failure?: boolean; + ignore_missing?: boolean; + if?: string; + tag?: string; + [key: string]: unknown; +} +export const ESProcessorOptions = z + .object({ + /** + * An array of items to execute if the processor fails. + */ + on_failure: z.array(ESProcessorItem).optional(), + /** + * If true, the processor continues to the next processor if the current processor fails. + */ + ignore_failure: z.boolean().optional(), + /** + * If true, the processor continues to the next processor if the field is missing. + */ + ignore_missing: z.boolean().optional(), + /** + * Conditionally execute the processor. + */ + if: z.string().optional(), + /** + * A tag to assign to the document after processing. + */ + tag: z.string().optional(), + }) + .catchall(z.unknown()); diff --git a/x-pack/plugins/integration_assistant/common/api/model/response_schemas.schema.yaml b/x-pack/plugins/integration_assistant/common/api/model/response_schemas.schema.yaml new file mode 100644 index 00000000000000..100581cd21ceb4 --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/model/response_schemas.schema.yaml @@ -0,0 +1,65 @@ +openapi: 3.0.3 +info: + title: Response Schemas. + version: "not applicable" +paths: {} +components: + x-codegen-enabled: false + schemas: + EcsMappingAPIResponse: + type: object + required: + - results + properties: + results: + type: object + required: + - mapping + - pipeline + properties: + mapping: + $ref: "./common_attributes.schema.yaml#/components/schemas/Mapping" + pipeline: + $ref: "./common_attributes.schema.yaml#/components/schemas/Pipeline" + + CategorizationAPIResponse: + type: object + required: + - results + properties: + results: + type: object + required: + - docs + - pipeline + properties: + docs: + $ref: "./common_attributes.schema.yaml#/components/schemas/Docs" + pipeline: + $ref: "./common_attributes.schema.yaml#/components/schemas/Pipeline" + + RelatedAPIResponse: + type: object + required: + - results + properties: + results: + type: object + required: + - docs + - pipeline + properties: + docs: + $ref: "./common_attributes.schema.yaml#/components/schemas/Docs" + pipeline: + $ref: "./common_attributes.schema.yaml#/components/schemas/Pipeline" + + CheckPipelineAPIResponse: + type: object + required: + - pipelineResults + properties: + pipelineResults: + $ref: "./common_attributes.schema.yaml#/components/schemas/PipelineResults" + errors: + $ref: "./common_attributes.schema.yaml#/components/schemas/Errors" diff --git a/x-pack/plugins/integration_assistant/common/api/model/response_schemas.ts b/x-pack/plugins/integration_assistant/common/api/model/response_schemas.ts new file mode 100644 index 00000000000000..f8a42d2081488e --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/model/response_schemas.ts @@ -0,0 +1,49 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Response Schemas. + * version: not applicable + */ + +import { z } from 'zod'; + +import { Docs, Errors, Mapping, Pipeline, PipelineResults } from './common_attributes'; + +export type EcsMappingAPIResponse = z.infer; +export const EcsMappingAPIResponse = z.object({ + results: z.object({ + mapping: Mapping, + pipeline: Pipeline, + }), +}); + +export type CategorizationAPIResponse = z.infer; +export const CategorizationAPIResponse = z.object({ + results: z.object({ + docs: Docs, + pipeline: Pipeline, + }), +}); + +export type RelatedAPIResponse = z.infer; +export const RelatedAPIResponse = z.object({ + results: z.object({ + docs: Docs, + pipeline: Pipeline, + }), +}); + +export type CheckPipelineAPIResponse = z.infer; +export const CheckPipelineAPIResponse = z.object({ + pipelineResults: PipelineResults, + errors: Errors.optional(), +}); diff --git a/x-pack/plugins/integration_assistant/common/api/related/related_route.schema.yaml b/x-pack/plugins/integration_assistant/common/api/related/related_route.schema.yaml new file mode 100644 index 00000000000000..3172d9f9ba8127 --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/related/related_route.schema.yaml @@ -0,0 +1,43 @@ +openapi: 3.0.3 +info: + title: Integration Assistatnt Related API endpoint + version: "1" +paths: + /api/integration_assistant/related: + post: + summary: Builds related.* fields for integration with the given input samples + operationId: Related + x-codegen-enabled: false + description: Add Related mappings for the given samples. + tags: + - Related API + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - packageName + - datastreamName + - rawSamples + - currentPipeline + - connectorId + properties: + packageName: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/PackageName" + datastreamName: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/DatastreamName" + rawSamples: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/RawSamples" + currentPipeline: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/Pipeline" + connectorId: + $ref: "../model/common_attributes.schema.yaml#/components/schemas/Connector" + responses: + 200: + description: Indicates a successful call. + content: + application/json: + schema: + $ref: "../model/response_schemas.schema.yaml#/components/schemas/RelatedAPIResponse" diff --git a/x-pack/plugins/integration_assistant/common/api/related/related_route.ts b/x-pack/plugins/integration_assistant/common/api/related/related_route.ts new file mode 100644 index 00000000000000..2b8c46866cc7be --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/related/related_route.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +import { + Connector, + DatastreamName, + PackageName, + Pipeline, + RawSamples, +} from '../model/common_attributes'; +import { RelatedAPIResponse } from '../model/response_schemas'; + +export type RelatedRequestBody = z.infer; +export const RelatedRequestBody = z.object({ + packageName: PackageName, + datastreamName: DatastreamName, + rawSamples: RawSamples, + currentPipeline: Pipeline, + connectorId: Connector, +}); +export type RelatedRequestBodyInput = z.input; + +export type RelatedResponse = z.infer; +export const RelatedResponse = RelatedAPIResponse; diff --git a/x-pack/plugins/integration_assistant/common/index.ts b/x-pack/plugins/integration_assistant/common/index.ts index 99b6cb8793a489..d5e72ede8e164f 100644 --- a/x-pack/plugins/integration_assistant/common/index.ts +++ b/x-pack/plugins/integration_assistant/common/index.ts @@ -5,31 +5,28 @@ * 2.0. */ -export type { - BuildIntegrationApiRequest, - EcsMappingApiRequest, - CategorizationApiRequest, - RelatedApiRequest, - CategorizationApiResponse, - RelatedApiResponse, - EcsMappingApiResponse, - Pipeline, - ESProcessorItem, - ESProcessorOptions, - DataStream, - Integration, - InputTypes, - TestPipelineApiRequest, - TestPipelineApiResponse, -} from './types'; +export { BuildIntegrationRequestBody } from './api/build_integration/build_integration'; +export { + CategorizationRequestBody, + CategorizationResponse, +} from './api/categorization/categorization_route'; +export { + CheckPipelineRequestBody, + CheckPipelineResponse, +} from './api/check_pipeline/check_pipeline'; +export { EcsMappingRequestBody, EcsMappingResponse } from './api/ecs/ecs_route'; +export { RelatedRequestBody, RelatedResponse } from './api/related/related_route'; + +export type { Datastream, InputType, Integration, Pipeline } from './api/model/common_attributes'; +export type { ESProcessorItem } from './api/model/processor_attributes'; export { - PLUGIN_ID, - INTEGRATION_ASSISTANT_APP_ROUTE, - ECS_GRAPH_PATH, CATEGORIZATION_GRAPH_PATH, + ECS_GRAPH_PATH, + INTEGRATION_ASSISTANT_APP_ROUTE, + INTEGRATION_ASSISTANT_BASE_PATH, + INTEGRATION_BUILDER_PATH, + PLUGIN_ID, RELATED_GRAPH_PATH, TEST_PIPELINE_PATH, - INTEGRATION_BUILDER_PATH, - INTEGRATION_ASSISTANT_BASE_PATH, } from './constants'; diff --git a/x-pack/plugins/integration_assistant/common/types.ts b/x-pack/plugins/integration_assistant/common/types.ts deleted file mode 100644 index 50da197460e1ef..00000000000000 --- a/x-pack/plugins/integration_assistant/common/types.ts +++ /dev/null @@ -1,119 +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 interface ESProcessorOptions { - on_failure?: ESProcessorItem[]; - ignore_failure?: boolean; - ignore_missing?: boolean; - if?: string; - tag?: string; - [key: string]: unknown; -} - -export interface ESProcessorItem { - [processorName: string]: ESProcessorOptions; -} - -export interface Pipeline { - name?: string; - description?: string; - version?: number; - processors: ESProcessorItem[]; - on_failure?: ESProcessorItem[]; -} - -export enum InputTypes { - Cloudwatch = 'aws-cloudwatch', - S3 = 'aws-s3', - AzureBlobStorage = 'azure-blob-storage', - EventHub = 'azure-eventhub', - Cloudfoundry = 'cloudfoundry', - FileStream = 'filestream', - PubSub = 'gcp-pubsub', - GoogleCloudStorage = 'gcs', - HTTPListener = 'http_endpoint', - Journald = 'journald', - Kafka = 'kafka', - TCP = 'tcp', - UDP = 'udp', -} - -export interface DataStream { - name: string; - title: string; - description: string; - inputTypes: InputTypes[]; - rawSamples: string[]; - pipeline: object; - docs: object[]; -} - -export interface Integration { - name: string; - title: string; - description: string; - dataStreams: DataStream[]; - logo?: string; -} - -// Server Request Schemas -export interface BuildIntegrationApiRequest { - integration: Integration; -} - -export interface EcsMappingApiRequest { - packageName: string; - dataStreamName: string; - rawSamples: string[]; - mapping?: object; -} - -export interface CategorizationApiRequest { - packageName: string; - dataStreamName: string; - rawSamples: string[]; - currentPipeline: object; -} - -export interface RelatedApiRequest { - packageName: string; - dataStreamName: string; - rawSamples: string[]; - currentPipeline: object; -} - -export interface TestPipelineApiRequest { - rawSamples: string[]; - currentPipeline: Pipeline; -} - -// Server Response Schemas -export interface CategorizationApiResponse { - results: { - pipeline: object; - docs: object[]; - }; -} - -export interface RelatedApiResponse { - results: { - pipeline: object; - docs: object[]; - }; -} - -export interface EcsMappingApiResponse { - results: { - mapping: object; - pipeline: object; - }; -} - -export interface TestPipelineApiResponse { - pipelineResults: object[]; - errors?: object[]; -} diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts index 8c7347a8b5058e..2c8e7283d47280 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts @@ -5,21 +5,21 @@ * 2.0. */ -import type { StateGraphArgs } from '@langchain/langgraph'; -import { StateGraph, END, START } from '@langchain/langgraph'; import type { ActionsClientChatOpenAI, ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; +import type { StateGraphArgs } from '@langchain/langgraph'; +import { END, START, StateGraph } from '@langchain/langgraph'; +import type { EcsMappingState } from '../../types'; +import { mergeSamples, modifySamples } from '../../util/samples'; import { ECS_EXAMPLE_ANSWER, ECS_FIELDS } from './constants'; -import { modifySamples, mergeSamples } from '../../util/samples'; -import { createPipeline } from './pipeline'; -import { handleEcsMapping } from './mapping'; import { handleDuplicates } from './duplicates'; -import { handleMissingKeys } from './missing'; import { handleInvalidEcs } from './invalid'; +import { handleEcsMapping } from './mapping'; +import { handleMissingKeys } from './missing'; +import { createPipeline } from './pipeline'; import { handleValidateMappings } from './validate'; -import type { EcsMappingState } from '../../types'; const graphState: StateGraphArgs['channels'] = { ecs: { diff --git a/x-pack/plugins/integration_assistant/server/integration_builder/agent.ts b/x-pack/plugins/integration_assistant/server/integration_builder/agent.ts index 6d3282e00f18a0..2f622eec103e57 100644 --- a/x-pack/plugins/integration_assistant/server/integration_builder/agent.ts +++ b/x-pack/plugins/integration_assistant/server/integration_builder/agent.ts @@ -6,10 +6,10 @@ */ import { join as joinPath } from 'path'; -import type { InputTypes } from '../../common'; -import { ensureDirSync, createSync, readSync } from '../util'; +import type { InputType } from '../../common'; +import { createSync, ensureDirSync, readSync } from '../util'; -export function createAgentInput(specificDataStreamDir: string, inputTypes: InputTypes[]): void { +export function createAgentInput(specificDataStreamDir: string, inputTypes: InputType[]): void { const agentDir = joinPath(specificDataStreamDir, 'agent', 'stream'); const agentTemplatesDir = joinPath(__dirname, '../templates/agent'); ensureDirSync(agentDir); diff --git a/x-pack/plugins/integration_assistant/server/integration_builder/build_integration.ts b/x-pack/plugins/integration_assistant/server/integration_builder/build_integration.ts index d2e29f769dd9a5..05018d056b4985 100644 --- a/x-pack/plugins/integration_assistant/server/integration_builder/build_integration.ts +++ b/x-pack/plugins/integration_assistant/server/integration_builder/build_integration.ts @@ -9,7 +9,7 @@ import AdmZip from 'adm-zip'; import nunjucks from 'nunjucks'; import { tmpdir } from 'os'; import { join as joinPath } from 'path'; -import type { DataStream, Integration } from '../../common'; +import type { Datastream, Integration } from '../../common'; import { copySync, createSync, ensureDirSync, generateUniqueId } from '../util'; import { createAgentInput } from './agent'; import { createDatastream } from './data_stream'; @@ -113,7 +113,7 @@ async function createZipArchive(tmpPackageDir: string): Promise { function createPackageManifest(packageDir: string, integration: Integration): void { const uniqueInputs: { [key: string]: { type: string; title: string; description: string } } = {}; - integration.dataStreams.forEach((dataStream: DataStream) => { + integration.dataStreams.forEach((dataStream: Datastream) => { dataStream.inputTypes.forEach((inputType: string) => { if (!uniqueInputs[inputType]) { uniqueInputs[inputType] = { diff --git a/x-pack/plugins/integration_assistant/server/integration_builder/data_stream.ts b/x-pack/plugins/integration_assistant/server/integration_builder/data_stream.ts index fa9a24475e92eb..8236666aec321a 100644 --- a/x-pack/plugins/integration_assistant/server/integration_builder/data_stream.ts +++ b/x-pack/plugins/integration_assistant/server/integration_builder/data_stream.ts @@ -7,13 +7,13 @@ import nunjucks from 'nunjucks'; import { join as joinPath } from 'path'; -import type { DataStream } from '../../common'; +import type { Datastream } from '../../common'; import { copySync, createSync, ensureDirSync, listDirSync } from '../util'; export function createDatastream( packageName: string, specificDataStreamDir: string, - dataStream: DataStream + dataStream: Datastream ): void { const dataStreamName = dataStream.name; const pipelineDir = joinPath(specificDataStreamDir, 'elasticsearch', 'ingest_pipeline'); diff --git a/x-pack/plugins/integration_assistant/server/integration_builder/pipeline.ts b/x-pack/plugins/integration_assistant/server/integration_builder/pipeline.ts index 805535322b8e7f..d733fd001be02f 100644 --- a/x-pack/plugins/integration_assistant/server/integration_builder/pipeline.ts +++ b/x-pack/plugins/integration_assistant/server/integration_builder/pipeline.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { join as joinPath } from 'path'; import yaml from 'js-yaml'; import { createSync } from '../util'; diff --git a/x-pack/plugins/integration_assistant/server/routes/build_integration_routes.ts b/x-pack/plugins/integration_assistant/server/routes/build_integration_routes.ts index 191f189bacf8d3..c3943c7d6398d3 100644 --- a/x-pack/plugins/integration_assistant/server/routes/build_integration_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/build_integration_routes.ts @@ -5,12 +5,11 @@ * 2.0. */ -import { schema } from '@kbn/config-schema'; import type { IRouter } from '@kbn/core/server'; -import type { BuildIntegrationApiRequest } from '../../common'; -import { INTEGRATION_BUILDER_PATH } from '../../common'; +import { BuildIntegrationRequestBody, INTEGRATION_BUILDER_PATH } from '../../common'; import { buildPackage } from '../integration_builder'; import type { IntegrationAssistantRouteHandlerContext } from '../plugin'; +import { buildRouteValidationWithZod } from '../util/route_validation'; export function registerIntegrationBuilderRoutes( router: IRouter @@ -25,42 +24,12 @@ export function registerIntegrationBuilderRoutes( version: '1', validate: { request: { - body: schema.object({ - integration: schema.object({ - name: schema.string(), - title: schema.string(), - description: schema.string(), - logo: schema.maybe(schema.string()), - dataStreams: schema.arrayOf( - schema.object({ - name: schema.string(), - title: schema.string(), - description: schema.string(), - inputTypes: schema.arrayOf(schema.string()), - rawSamples: schema.arrayOf(schema.string()), - pipeline: schema.object({ - name: schema.maybe(schema.string()), - description: schema.maybe(schema.string()), - version: schema.maybe(schema.number()), - processors: schema.arrayOf( - schema.recordOf(schema.string(), schema.object({}, { unknowns: 'allow' })) - ), - on_failure: schema.maybe( - schema.arrayOf( - schema.recordOf(schema.string(), schema.object({}, { unknowns: 'allow' })) - ) - ), - }), - docs: schema.arrayOf(schema.object({}, { unknowns: 'allow' })), - }) - ), - }), - }), + body: buildRouteValidationWithZod(BuildIntegrationRequestBody), }, }, }, async (_, request, response) => { - const { integration } = request.body as BuildIntegrationApiRequest; + const { integration } = request.body; try { const zippedIntegration = await buildPackage(integration); return response.custom({ statusCode: 200, body: zippedIntegration }); diff --git a/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts b/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts index 4feb1c8b3bd8fd..5ec9dc1b758efc 100644 --- a/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts @@ -5,18 +5,21 @@ * 2.0. */ -import { schema } from '@kbn/config-schema'; -import type { IRouter } from '@kbn/core/server'; +import type { IKibanaResponse, IRouter } from '@kbn/core/server'; import { getRequestAbortedSignal } from '@kbn/data-plugin/server'; import { ActionsClientChatOpenAI, ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -import type { CategorizationApiRequest, CategorizationApiResponse } from '../../common'; -import { CATEGORIZATION_GRAPH_PATH } from '../../common'; +import { + CATEGORIZATION_GRAPH_PATH, + CategorizationRequestBody, + CategorizationResponse, +} from '../../common'; import { ROUTE_HANDLER_TIMEOUT } from '../constants'; import { getCategorizationGraph } from '../graphs/categorization'; import type { IntegrationAssistantRouteHandlerContext } from '../plugin'; +import { buildRouteValidationWithZod } from '../util/route_validation'; export function registerCategorizationRoutes( router: IRouter @@ -36,64 +39,53 @@ export function registerCategorizationRoutes( version: '1', validate: { request: { - body: schema.object({ - packageName: schema.string(), - dataStreamName: schema.string(), - rawSamples: schema.arrayOf(schema.string()), - currentPipeline: schema.any(), - connectorId: schema.maybe(schema.string()), - model: schema.maybe(schema.string()), - region: schema.maybe(schema.string()), - }), + body: buildRouteValidationWithZod(CategorizationRequestBody), }, }, }, - async (context, req, res) => { - const { packageName, dataStreamName, rawSamples, currentPipeline } = - req.body as CategorizationApiRequest; - + async (context, req, res): Promise> => { + const { packageName, datastreamName, rawSamples, currentPipeline } = req.body; const services = await context.resolve(['core']); const { client } = services.core.elasticsearch; const { getStartServices, logger } = await context.integrationAssistant; const [, { actions: actionsPlugin }] = await getStartServices(); - const actionsClient = await actionsPlugin.getActionsClientWithRequest(req); - const connector = req.body.connectorId - ? await actionsClient.get({ id: req.body.connectorId }) - : (await actionsClient.getAll()).filter( - (connectorItem) => connectorItem.actionTypeId === '.bedrock' - )[0]; - const abortSignal = getRequestAbortedSignal(req.events.aborted$); - const isOpenAI = connector.actionTypeId === '.gen-ai'; - const llmClass = isOpenAI ? ActionsClientChatOpenAI : ActionsClientSimpleChatModel; + try { + const actionsClient = await actionsPlugin.getActionsClientWithRequest(req); + const connector = req.body.connectorId + ? await actionsClient.get({ id: req.body.connectorId }) + : (await actionsClient.getAll()).filter( + (connectorItem) => connectorItem.actionTypeId === '.bedrock' + )[0]; + + const abortSignal = getRequestAbortedSignal(req.events.aborted$); + const isOpenAI = connector.actionTypeId === '.gen-ai'; + const llmClass = isOpenAI ? ActionsClientChatOpenAI : ActionsClientSimpleChatModel; - const model = new llmClass({ - actions: actionsPlugin, - connectorId: connector.id, - request: req, - logger, - llmType: isOpenAI ? 'openai' : 'bedrock', - model: req.body.model || connector.config?.defaultModel, - temperature: 0.05, - maxTokens: 4096, - signal: abortSignal, - streaming: false, - }); + const model = new llmClass({ + actions: actionsPlugin, + connectorId: connector.id, + request: req, + logger, + llmType: isOpenAI ? 'openai' : 'bedrock', + model: connector.config?.defaultModel, + temperature: 0.05, + maxTokens: 4096, + signal: abortSignal, + streaming: false, + }); - const graph = await getCategorizationGraph(client, model); - let results = { results: { docs: {}, pipeline: {} } }; - try { - results = (await graph.invoke({ + const graph = await getCategorizationGraph(client, model); + const results = await graph.invoke({ packageName, - dataStreamName, + datastreamName, rawSamples, currentPipeline, - })) as CategorizationApiResponse; + }); + return res.ok({ body: CategorizationResponse.parse(results) }); } catch (e) { return res.badRequest({ body: e }); } - - return res.ok({ body: results }); } ); } diff --git a/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts b/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts index d62e31389af464..1ee7659b3598b8 100644 --- a/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts @@ -5,18 +5,17 @@ * 2.0. */ -import { schema } from '@kbn/config-schema'; -import type { IRouter } from '@kbn/core/server'; +import type { IKibanaResponse, IRouter } from '@kbn/core/server'; import { getRequestAbortedSignal } from '@kbn/data-plugin/server'; import { ActionsClientChatOpenAI, ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -import { ECS_GRAPH_PATH } from '../../common'; -import type { EcsMappingApiRequest, EcsMappingApiResponse } from '../../common/types'; +import { ECS_GRAPH_PATH, EcsMappingRequestBody, EcsMappingResponse } from '../../common'; import { ROUTE_HANDLER_TIMEOUT } from '../constants'; import { getEcsGraph } from '../graphs/ecs'; import type { IntegrationAssistantRouteHandlerContext } from '../plugin'; +import { buildRouteValidationWithZod } from '../util/route_validation'; export function registerEcsRoutes(router: IRouter) { router.versioned @@ -34,70 +33,60 @@ export function registerEcsRoutes(router: IRouter { - const { packageName, dataStreamName, rawSamples, mapping } = - req.body as EcsMappingApiRequest; - + async (context, req, res): Promise> => { + const { packageName, datastreamName, rawSamples, mapping } = req.body; const { getStartServices, logger } = await context.integrationAssistant; const [, { actions: actionsPlugin }] = await getStartServices(); - const actionsClient = await actionsPlugin.getActionsClientWithRequest(req); - const connector = req.body.connectorId - ? await actionsClient.get({ id: req.body.connectorId }) - : (await actionsClient.getAll()).filter( - (connectorItem) => connectorItem.actionTypeId === '.bedrock' - )[0]; - const abortSignal = getRequestAbortedSignal(req.events.aborted$); - const isOpenAI = connector.actionTypeId === '.gen-ai'; - const llmClass = isOpenAI ? ActionsClientChatOpenAI : ActionsClientSimpleChatModel; + try { + const actionsClient = await actionsPlugin.getActionsClientWithRequest(req); + const connector = req.body.connectorId + ? await actionsClient.get({ id: req.body.connectorId }) + : (await actionsClient.getAll()).filter( + (connectorItem) => connectorItem.actionTypeId === '.bedrock' + )[0]; - const model = new llmClass({ - actions: actionsPlugin, - connectorId: connector.id, - request: req, - logger, - llmType: isOpenAI ? 'openai' : 'bedrock', - model: req.body.model || connector.config?.defaultModel, - temperature: 0.05, - maxTokens: 4096, - signal: abortSignal, - streaming: false, - }); + const abortSignal = getRequestAbortedSignal(req.events.aborted$); + const isOpenAI = connector.actionTypeId === '.gen-ai'; + const llmClass = isOpenAI ? ActionsClientChatOpenAI : ActionsClientSimpleChatModel; - const graph = await getEcsGraph(model); - let results = { results: { mapping: {}, pipeline: {} } }; - try { + const model = new llmClass({ + actions: actionsPlugin, + connectorId: connector.id, + request: req, + logger, + llmType: isOpenAI ? 'openai' : 'bedrock', + model: connector.config?.defaultModel, + temperature: 0.05, + maxTokens: 4096, + signal: abortSignal, + streaming: false, + }); + + const graph = await getEcsGraph(model); + + let results; if (req.body?.mapping) { - results = (await graph.invoke({ + results = await graph.invoke({ packageName, - dataStreamName, + datastreamName, rawSamples, mapping, - })) as EcsMappingApiResponse; + }); } else - results = (await graph.invoke({ + results = await graph.invoke({ packageName, - dataStreamName, + datastreamName, rawSamples, - })) as EcsMappingApiResponse; + }); + return res.ok({ body: EcsMappingResponse.parse(results) }); } catch (e) { return res.badRequest({ body: e }); } - - return res.ok({ body: results }); } ); } diff --git a/x-pack/plugins/integration_assistant/server/routes/pipeline_routes.ts b/x-pack/plugins/integration_assistant/server/routes/pipeline_routes.ts index 17e4f667a6df5a..4b4ccc0a859a55 100644 --- a/x-pack/plugins/integration_assistant/server/routes/pipeline_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/pipeline_routes.ts @@ -5,13 +5,12 @@ * 2.0. */ -import { schema } from '@kbn/config-schema'; -import type { IRouter } from '@kbn/core/server'; -import { TEST_PIPELINE_PATH } from '../../common'; -import type { TestPipelineApiRequest, TestPipelineApiResponse } from '../../common/types'; +import type { IKibanaResponse, IRouter } from '@kbn/core/server'; +import { CheckPipelineRequestBody, CheckPipelineResponse, TEST_PIPELINE_PATH } from '../../common'; import { ROUTE_HANDLER_TIMEOUT } from '../constants'; import type { IntegrationAssistantRouteHandlerContext } from '../plugin'; import { testPipeline } from '../util/pipeline'; +import { buildRouteValidationWithZod } from '../util/route_validation'; export function registerPipelineRoutes(router: IRouter) { router.versioned @@ -29,32 +28,23 @@ export function registerPipelineRoutes(router: IRouter { - const { rawSamples, currentPipeline } = req.body as TestPipelineApiRequest; + async (context, req, res): Promise> => { + const { rawSamples, pipeline } = req.body; const services = await context.resolve(['core']); const { client } = services.core.elasticsearch; - let results: TestPipelineApiResponse = { pipelineResults: [], errors: [] }; try { - results = (await testPipeline( - rawSamples, - currentPipeline, - client - )) as TestPipelineApiResponse; + const results = await testPipeline(rawSamples, pipeline, client); if (results?.errors && results.errors.length > 0) { return res.badRequest({ body: JSON.stringify(results.errors) }); } + return res.ok({ body: CheckPipelineResponse.parse(results) }); } catch (e) { return res.badRequest({ body: e }); } - - return res.ok({ body: results }); } ); } diff --git a/x-pack/plugins/integration_assistant/server/routes/related_routes.ts b/x-pack/plugins/integration_assistant/server/routes/related_routes.ts index 934b9711027eeb..90533742e8ff70 100644 --- a/x-pack/plugins/integration_assistant/server/routes/related_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/related_routes.ts @@ -5,18 +5,17 @@ * 2.0. */ -import { schema } from '@kbn/config-schema'; -import type { IRouter } from '@kbn/core/server'; +import type { IKibanaResponse, IRouter } from '@kbn/core/server'; import { getRequestAbortedSignal } from '@kbn/data-plugin/server'; import { ActionsClientChatOpenAI, ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -import { RELATED_GRAPH_PATH } from '../../common'; -import type { RelatedApiRequest, RelatedApiResponse } from '../../common/types'; +import { RELATED_GRAPH_PATH, RelatedRequestBody, RelatedResponse } from '../../common'; import { ROUTE_HANDLER_TIMEOUT } from '../constants'; import { getRelatedGraph } from '../graphs/related'; import type { IntegrationAssistantRouteHandlerContext } from '../plugin'; +import { buildRouteValidationWithZod } from '../util/route_validation'; export function registerRelatedRoutes(router: IRouter) { router.versioned @@ -34,65 +33,52 @@ export function registerRelatedRoutes(router: IRouter { - const { packageName, dataStreamName, rawSamples, currentPipeline } = - req.body as RelatedApiRequest; - + async (context, req, res): Promise> => { + const { packageName, datastreamName, rawSamples, currentPipeline } = req.body; const services = await context.resolve(['core']); const { client } = services.core.elasticsearch; const { getStartServices, logger } = await context.integrationAssistant; const [, { actions: actionsPlugin }] = await getStartServices(); - const actionsClient = await actionsPlugin.getActionsClientWithRequest(req); - const connector = req.body.connectorId - ? await actionsClient.get({ id: req.body.connectorId }) - : (await actionsClient.getAll()).filter( - (connectorItem) => connectorItem.actionTypeId === '.bedrock' - )[0]; + try { + const actionsClient = await actionsPlugin.getActionsClientWithRequest(req); + const connector = req.body.connectorId + ? await actionsClient.get({ id: req.body.connectorId }) + : (await actionsClient.getAll()).filter( + (connectorItem) => connectorItem.actionTypeId === '.bedrock' + )[0]; - const isOpenAI = connector.actionTypeId === '.gen-ai'; - const llmClass = isOpenAI ? ActionsClientChatOpenAI : ActionsClientSimpleChatModel; - const abortSignal = getRequestAbortedSignal(req.events.aborted$); + const isOpenAI = connector.actionTypeId === '.gen-ai'; + const llmClass = isOpenAI ? ActionsClientChatOpenAI : ActionsClientSimpleChatModel; + const abortSignal = getRequestAbortedSignal(req.events.aborted$); - const model = new llmClass({ - actions: actionsPlugin, - connectorId: connector.id, - request: req, - logger, - llmType: isOpenAI ? 'openai' : 'bedrock', - model: req.body.model || connector.config?.defaultModel, - temperature: 0.05, - maxTokens: 4096, - signal: abortSignal, - streaming: false, - }); + const model = new llmClass({ + actions: actionsPlugin, + connectorId: connector.id, + request: req, + logger, + llmType: isOpenAI ? 'openai' : 'bedrock', + model: connector.config?.defaultModel, + temperature: 0.05, + maxTokens: 4096, + signal: abortSignal, + streaming: false, + }); - const graph = await getRelatedGraph(client, model); - let results = { results: { docs: {}, pipeline: {} } }; - try { - results = (await graph.invoke({ + const graph = await getRelatedGraph(client, model); + const results = await graph.invoke({ packageName, - dataStreamName, + datastreamName, rawSamples, currentPipeline, - })) as RelatedApiResponse; + }); + return res.ok({ body: RelatedResponse.parse(results) }); } catch (e) { return res.badRequest({ body: e }); } - - return res.ok({ body: results }); } ); } diff --git a/x-pack/plugins/integration_assistant/server/util/route_validation.ts b/x-pack/plugins/integration_assistant/server/util/route_validation.ts new file mode 100644 index 00000000000000..e9f9c08b74c815 --- /dev/null +++ b/x-pack/plugins/integration_assistant/server/util/route_validation.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RouteValidationFunction, RouteValidationResultFactory } from '@kbn/core/server'; +import { stringifyZodError } from '@kbn/zod-helpers'; +import type { TypeOf, ZodType } from 'zod'; + +export const buildRouteValidationWithZod = + >(schema: T): RouteValidationFunction => + (inputValue: unknown, validationResult: RouteValidationResultFactory) => { + const decoded = schema.safeParse(inputValue); + if (decoded.success) { + return validationResult.ok(decoded.data); + } else { + return validationResult.badRequest(stringifyZodError(decoded.error)); + } + }; diff --git a/x-pack/plugins/integration_assistant/tsconfig.json b/x-pack/plugins/integration_assistant/tsconfig.json index 67a763a73f7f33..515611f12f1669 100644 --- a/x-pack/plugins/integration_assistant/tsconfig.json +++ b/x-pack/plugins/integration_assistant/tsconfig.json @@ -17,6 +17,7 @@ "@kbn/langchain", "@kbn/core-elasticsearch-server", "@kbn/actions-plugin", - "@kbn/data-plugin" + "@kbn/data-plugin", + "@kbn/zod-helpers" ] } From 7a0065d5b67805c82695f4cce0998a89f77a4ae7 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 18 Jun 2024 22:22:19 +0200 Subject: [PATCH 059/123] [Security Solution] Add missing Lists API OpenAPI specifications (#185865) **Resolves:** https://github.com/elastic/kibana/issues/183821 ## Summary This PR adds missing OpenAPI specifications for Lists API which are the following - `POST /api/lists` - `GET /api/lists` - `PUT /api/lists` - `DELETE /api/lists` - `PATCH /api/lists` - `GET /api/lists/_find` - `GET /api/lists/privileges` - `POST /api/lists/items` - `GET /api/lists/items` - `PUT /api/lists/items` - `DELETE /api/lists/items` - `PATCH /api/lists/items` - `POST /api/lists/items/_export` - `POST /api/lists/items/_import` - `GET /api/lists/items/_find` - `POST /api/lists/index` - `GET /api/lists/index` - `DELETE /api/lists/index` **Note:** Code generation is enabled for the added specs to verify that it works and produces expected results. Generated Zod schemas and types aren't integrated in the route's code. --- .../security_solution_codegen.sh | 12 ++ .github/CODEOWNERS | 2 + package.json | 2 + packages/kbn-openapi-common/README.md | 3 + packages/kbn-openapi-common/kibana.jsonc | 5 + packages/kbn-openapi-common/package.json | 11 ++ .../schemas/error_responses.gen.ts | 31 +++++ .../schemas/error_responses.schema.yaml | 32 +++++ .../schemas/primitives.gen.ts | 33 +++++ .../schemas/primitives.schema.yaml | 18 +++ .../scripts/openapi_generate.js | 22 +++ packages/kbn-openapi-common/tsconfig.json | 10 ++ .../README.md | 20 +++ .../api/create_list/create_list.gen.ts | 43 ++++++ .../api/create_list/create_list.schema.yaml | 82 ++++++++++++ .../create_list_index.gen.ts | 23 ++++ .../create_list_index.schema.yaml | 56 ++++++++ .../create_list_item/create_list_item.gen.ts | 37 ++++++ .../create_list_item.schema.yaml | 78 +++++++++++ .../api/delete_list/delete_list.gen.ts | 36 +++++ .../api/delete_list/delete_list.schema.yaml | 71 ++++++++++ .../delete_list_index.gen.ts | 23 ++++ .../delete_list_index.schema.yaml | 56 ++++++++ .../delete_list_item/delete_list_item.gen.ts | 45 +++++++ .../delete_list_item.schema.yaml | 83 ++++++++++++ .../export_list_item/export_list_item.gen.ts | 29 ++++ .../export_list_item.schema.yaml | 61 +++++++++ .../api/find_list/find_list.gen.ts | 70 ++++++++++ .../api/find_list/find_list.schema.yaml | 119 +++++++++++++++++ .../api/find_list_item/find_list_item.gen.ts | 75 +++++++++++ .../find_list_item/find_list_item.schema.yaml | 125 ++++++++++++++++++ .../get_list_privileges.gen.ts | 43 ++++++ .../get_list_privileges.schema.yaml | 115 ++++++++++++++++ .../import_list_item/import_list_item.gen.ts | 49 +++++++ .../import_list_item.schema.yaml | 102 ++++++++++++++ .../api/index.ts | 26 ++++ .../api/model/list_common.gen.ts | 73 ++++++++++ .../api/model/list_common.schema.yaml | 59 +++++++++ .../api/model/list_schemas.gen.ts | 67 ++++++++++ .../api/model/list_schemas.schema.yaml | 103 +++++++++++++++ .../api/patch_list/patch_list.gen.ts | 35 +++++ .../api/patch_list/patch_list.schema.yaml | 75 +++++++++++ .../patch_list_item/patch_list_item.gen.ts | 37 ++++++ .../patch_list_item.schema.yaml | 77 +++++++++++ .../api/read_list/read_list.gen.ts | 33 +++++ .../api/read_list/read_list.schema.yaml | 59 +++++++++ .../read_list_index/read_list_index.gen.ts | 24 ++++ .../read_list_index.schema.yaml | 58 ++++++++ .../api/read_list_item/read_list_item.gen.ts | 41 ++++++ .../read_list_item/read_list_item.schema.yaml | 75 +++++++++++ .../api/update_list/update_list.gen.ts | 35 +++++ .../api/update_list/update_list.schema.yaml | 77 +++++++++++ .../update_list_item/update_list_item.gen.ts | 33 +++++ .../update_list_item.schema.yaml | 71 ++++++++++ .../kibana.jsonc | 5 + .../package.json | 10 ++ .../scripts/openapi_generate.js | 22 +++ .../tsconfig.json | 10 ++ packages/kbn-zod-helpers/index.ts | 1 + .../src/build_route_validation_with_zod.ts | 48 +++++++ packages/kbn-zod-helpers/tsconfig.json | 4 +- tsconfig.base.json | 4 + x-pack/plugins/lists/common/api/index.ts | 16 --- .../values/create_list/create_list_route.ts | 15 --- .../create_list_index_route.ts | 10 -- .../create_list_item_route.ts | 10 -- .../values/delete_list/delete_list_route.ts | 10 -- .../delete_list_index_route.ts | 10 -- .../delete_list_item_route.ts | 18 --- .../api/values/find_list/find_list_route.ts | 10 -- .../find_list_item/find_list_item_route.ts | 18 --- .../import_list_item_route.ts | 13 -- .../api/values/patch_list/patch_list_route.ts | 10 -- .../patch_list_item/patch_list_item_route.ts | 10 -- .../api/values/read_list/read_list_route.ts | 10 -- .../read_list_index/read_list_index_route.ts | 10 -- .../read_list_item/read_list_item_route.ts | 18 --- .../values/update_list/update_list_route.ts | 10 -- .../update_list_item_route.ts | 10 -- .../request/create_list_schema.mock.ts | 8 +- .../request/update_list_schema.mock.ts | 6 +- .../server/routes/list/create_list_route.ts | 22 +-- .../server/routes/list/delete_list_route.ts | 23 ++-- .../routes/list/import_list_item_route.ts | 26 ++-- .../server/routes/list/patch_list_route.ts | 15 +-- .../server/routes/list/read_list_route.ts | 15 +-- .../server/routes/list/update_list_route.ts | 15 +-- .../list_index/create_list_index_route.ts | 10 +- .../list_index/delete_list_index_route.ts | 10 +- .../list_index/export_list_item_route.ts | 7 +- .../routes/list_index/find_list_route.ts | 16 +-- .../list_index/read_list_index_route.ts | 18 +-- .../list_item/create_list_item_route.ts | 19 ++- .../list_item/delete_list_item_route.ts | 29 ++-- .../routes/list_item/find_list_item_route.ts | 25 ++-- .../routes/list_item/patch_list_item_route.ts | 18 ++- .../routes/list_item/read_list_item_route.ts | 29 ++-- .../list_item/update_list_item_route.ts | 18 ++- x-pack/plugins/lists/tsconfig.json | 11 +- .../signals/create_signals_migration_route.ts | 2 +- .../signals/delete_signals_migration_route.ts | 2 +- .../finalize_signals_migration_route.ts | 2 +- .../get_signals_migration_status_route.ts | 2 +- .../signals/open_close_signals_route.ts | 2 +- .../routes/signals/query_signals_route.ts | 2 +- .../signals/set_alert_assignees_route.ts | 2 +- .../routes/signals/set_alert_tags_route.ts | 2 +- .../users/suggest_user_profiles_route.ts | 2 +- .../api/rules/bulk_actions/route.ts | 2 +- .../api/rules/bulk_create_rules/route.ts | 2 +- .../api/rules/bulk_delete_rules/route.ts | 2 +- .../api/rules/bulk_patch_rules/route.ts | 3 +- .../api/rules/bulk_update_rules/route.ts | 4 +- .../api/rules/create_rule/route.ts | 2 +- .../api/rules/delete_rule/route.ts | 2 +- .../api/rules/export_rules/route.ts | 4 +- .../api/rules/find_rules/route.ts | 3 +- .../api/rules/import_rules/route.ts | 2 +- .../api/rules/patch_rule/route.ts | 2 +- .../api/rules/read_rule/route.ts | 2 +- .../api/rules/update_rule/route.ts | 2 +- .../get_rule_execution_events_route.ts | 2 +- .../get_rule_execution_results_route.ts | 2 +- .../rule_preview/api/preview_rules/route.ts | 3 +- .../asset_criticality/routes/delete.ts | 2 +- .../asset_criticality/routes/get.ts | 2 +- .../asset_criticality/routes/upsert.ts | 2 +- .../risk_score/routes/calculation.ts | 2 +- .../risk_score/routes/entity_calculation.ts | 5 +- .../risk_score/routes/preview.ts | 3 +- .../build_validation/route_validation.ts | 13 -- .../items/find_list_items.ts | 49 +++---- yarn.lock | 8 ++ 133 files changed, 2964 insertions(+), 511 deletions(-) create mode 100644 packages/kbn-openapi-common/README.md create mode 100644 packages/kbn-openapi-common/kibana.jsonc create mode 100644 packages/kbn-openapi-common/package.json create mode 100644 packages/kbn-openapi-common/schemas/error_responses.gen.ts create mode 100644 packages/kbn-openapi-common/schemas/error_responses.schema.yaml create mode 100644 packages/kbn-openapi-common/schemas/primitives.gen.ts create mode 100644 packages/kbn-openapi-common/schemas/primitives.schema.yaml create mode 100644 packages/kbn-openapi-common/scripts/openapi_generate.js create mode 100644 packages/kbn-openapi-common/tsconfig.json create mode 100644 packages/kbn-securitysolution-lists-common/README.md create mode 100644 packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/find_list/find_list.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/find_list/find_list.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/get_list_privileges/get_list_privileges.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/get_list_privileges/get_list_privileges.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/index.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/model/list_schemas.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts create mode 100644 packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml create mode 100644 packages/kbn-securitysolution-lists-common/kibana.jsonc create mode 100644 packages/kbn-securitysolution-lists-common/package.json create mode 100644 packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js create mode 100644 packages/kbn-securitysolution-lists-common/tsconfig.json create mode 100644 packages/kbn-zod-helpers/src/build_route_validation_with_zod.ts delete mode 100644 x-pack/plugins/lists/common/api/values/create_list/create_list_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/create_list_index/create_list_index_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/create_list_item/create_list_item_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/delete_list/delete_list_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/delete_list_index/delete_list_index_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/delete_list_item/delete_list_item_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/find_list/find_list_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/find_list_item/find_list_item_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/import_list_item/import_list_item_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/patch_list/patch_list_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/patch_list_item/patch_list_item_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/read_list/read_list_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/read_list_index/read_list_index_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/read_list_item/read_list_item_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/update_list/update_list_route.ts delete mode 100644 x-pack/plugins/lists/common/api/values/update_list_item/update_list_item_route.ts diff --git a/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh b/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh index b36a9e52001e43..5a37c8a08d99a7 100755 --- a/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh +++ b/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh @@ -6,5 +6,17 @@ source .buildkite/scripts/common/util.sh echo --- Security Solution OpenAPI Code Generation +echo OpenAPI Common Package + +(cd packages/kbn-openapi-common && yarn openapi:generate) +check_for_changed_files "yarn openapi:generate" true + +echo Lists API Common Package + +(cd packages/kbn-securitysolution-lists-common && yarn openapi:generate) +check_for_changed_files "yarn openapi:generate" true + +echo Security Solution Plugin + (cd x-pack/plugins/security_solution && yarn openapi:generate) check_for_changed_files "yarn openapi:generate" true \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e519143df765df..690698e02a1421 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -622,6 +622,7 @@ x-pack/plugins/observability_solution/observability_shared @elastic/observabilit x-pack/test/security_api_integration/plugins/oidc_provider @elastic/kibana-security test/common/plugins/otel_metrics @elastic/obs-ux-infra_services-team packages/kbn-openapi-bundler @elastic/security-detection-rule-management +packages/kbn-openapi-common @elastic/security-detection-rule-management packages/kbn-openapi-generator @elastic/security-detection-rule-management packages/kbn-optimizer @elastic/kibana-operations packages/kbn-optimizer-webpack-helpers @elastic/kibana-operations @@ -752,6 +753,7 @@ packages/kbn-securitysolution-list-api @elastic/security-detection-engine packages/kbn-securitysolution-list-constants @elastic/security-detection-engine packages/kbn-securitysolution-list-hooks @elastic/security-detection-engine packages/kbn-securitysolution-list-utils @elastic/security-detection-engine +packages/kbn-securitysolution-lists-common @elastic/security-detection-engine packages/kbn-securitysolution-rules @elastic/security-detection-engine packages/kbn-securitysolution-t-grid @elastic/security-detection-engine packages/kbn-securitysolution-utils @elastic/security-detection-engine diff --git a/package.json b/package.json index 338db19ea67a11..48abd4ddd30b7c 100644 --- a/package.json +++ b/package.json @@ -647,6 +647,7 @@ "@kbn/observability-shared-plugin": "link:x-pack/plugins/observability_solution/observability_shared", "@kbn/oidc-provider-plugin": "link:x-pack/test/security_api_integration/plugins/oidc_provider", "@kbn/open-telemetry-instrumented-plugin": "link:test/common/plugins/otel_metrics", + "@kbn/openapi-common": "link:packages/kbn-openapi-common", "@kbn/osquery-io-ts-types": "link:packages/kbn-osquery-io-ts-types", "@kbn/osquery-plugin": "link:x-pack/plugins/osquery", "@kbn/paertial-results-example-plugin": "link:examples/partial_results_example", @@ -762,6 +763,7 @@ "@kbn/securitysolution-list-constants": "link:packages/kbn-securitysolution-list-constants", "@kbn/securitysolution-list-hooks": "link:packages/kbn-securitysolution-list-hooks", "@kbn/securitysolution-list-utils": "link:packages/kbn-securitysolution-list-utils", + "@kbn/securitysolution-lists-common": "link:packages/kbn-securitysolution-lists-common", "@kbn/securitysolution-rules": "link:packages/kbn-securitysolution-rules", "@kbn/securitysolution-t-grid": "link:packages/kbn-securitysolution-t-grid", "@kbn/securitysolution-utils": "link:packages/kbn-securitysolution-utils", diff --git a/packages/kbn-openapi-common/README.md b/packages/kbn-openapi-common/README.md new file mode 100644 index 00000000000000..7199904b486bef --- /dev/null +++ b/packages/kbn-openapi-common/README.md @@ -0,0 +1,3 @@ +# OpenAPI Common Schemas + +This package contains common reusable schemas like `NonEmptyString` to be reused by any OpenAPI specification defined inside Kibana. diff --git a/packages/kbn-openapi-common/kibana.jsonc b/packages/kbn-openapi-common/kibana.jsonc new file mode 100644 index 00000000000000..4254feb1b8a73f --- /dev/null +++ b/packages/kbn-openapi-common/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/openapi-common", + "owner": "@elastic/security-detection-rule-management" +} diff --git a/packages/kbn-openapi-common/package.json b/packages/kbn-openapi-common/package.json new file mode 100644 index 00000000000000..c90099eacadf06 --- /dev/null +++ b/packages/kbn-openapi-common/package.json @@ -0,0 +1,11 @@ +{ + "description": "OpenAPI common schemas for Kibana", + "license": "SSPL-1.0 OR Elastic License 2.0", + "name": "@kbn/openapi-common", + "private": true, + "version": "1.0.0", + "scripts": { + "openapi:generate": "node scripts/openapi_generate" + } +} + diff --git a/packages/kbn-openapi-common/schemas/error_responses.gen.ts b/packages/kbn-openapi-common/schemas/error_responses.gen.ts new file mode 100644 index 00000000000000..1555dcbb612e1d --- /dev/null +++ b/packages/kbn-openapi-common/schemas/error_responses.gen.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Error response schemas + * version: not applicable + */ + +import { z } from 'zod'; + +export type PlatformErrorResponse = z.infer; +export const PlatformErrorResponse = z.object({ + statusCode: z.number().int(), + error: z.string(), + message: z.string(), +}); + +export type SiemErrorResponse = z.infer; +export const SiemErrorResponse = z.object({ + status_code: z.number().int(), + message: z.string(), +}); diff --git a/packages/kbn-openapi-common/schemas/error_responses.schema.yaml b/packages/kbn-openapi-common/schemas/error_responses.schema.yaml new file mode 100644 index 00000000000000..9574103b9411e6 --- /dev/null +++ b/packages/kbn-openapi-common/schemas/error_responses.schema.yaml @@ -0,0 +1,32 @@ +openapi: 3.0.0 +info: + title: Error response schemas + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + PlatformErrorResponse: + type: object + properties: + statusCode: + type: integer + error: + type: string + message: + type: string + required: + - statusCode + - error + - message + + SiemErrorResponse: + type: object + properties: + status_code: + type: integer + message: + type: string + required: + - status_code + - message diff --git a/packages/kbn-openapi-common/schemas/primitives.gen.ts b/packages/kbn-openapi-common/schemas/primitives.gen.ts new file mode 100644 index 00000000000000..a9027448d7e778 --- /dev/null +++ b/packages/kbn-openapi-common/schemas/primitives.gen.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Shared Primitives Schema + * version: not applicable + */ + +import { z } from 'zod'; + +/** + * A string that is not empty and does not contain only whitespace + */ +export type NonEmptyString = z.infer; +export const NonEmptyString = z + .string() + .min(1) + .regex(/^(?! *$).+$/); + +/** + * A universally unique identifier + */ +export type UUID = z.infer; +export const UUID = z.string().uuid(); diff --git a/packages/kbn-openapi-common/schemas/primitives.schema.yaml b/packages/kbn-openapi-common/schemas/primitives.schema.yaml new file mode 100644 index 00000000000000..177ad2ed30ecca --- /dev/null +++ b/packages/kbn-openapi-common/schemas/primitives.schema.yaml @@ -0,0 +1,18 @@ +openapi: 3.0.0 +info: + title: Shared Primitives Schema + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + NonEmptyString: + type: string + pattern: ^(?! *$).+$ + minLength: 1 + description: A string that is not empty and does not contain only whitespace + + UUID: + type: string + format: uuid + description: A universally unique identifier diff --git a/packages/kbn-openapi-common/scripts/openapi_generate.js b/packages/kbn-openapi-common/scripts/openapi_generate.js new file mode 100644 index 00000000000000..e8e7ffca22ede2 --- /dev/null +++ b/packages/kbn-openapi-common/scripts/openapi_generate.js @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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. + */ + +require('../../../src/setup_node_env'); +const { resolve } = require('path'); +const { generate } = require('@kbn/openapi-generator'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await generate({ + title: 'OpenAPI Common Schemas (kbn-openapi-common)', + rootDir: ROOT, + sourceGlob: './schemas/**/*.schema.yaml', + templateName: 'zod_operation_schema', + }); +})(); diff --git a/packages/kbn-openapi-common/tsconfig.json b/packages/kbn-openapi-common/tsconfig.json new file mode 100644 index 00000000000000..168274f98f0585 --- /dev/null +++ b/packages/kbn-openapi-common/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "exclude": ["target/**/*"], + "extends": "../../tsconfig.base.json", + "include": ["**/*.ts"], + "kbn_references": [] +} diff --git a/packages/kbn-securitysolution-lists-common/README.md b/packages/kbn-securitysolution-lists-common/README.md new file mode 100644 index 00000000000000..4b7fbddc3ea064 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/README.md @@ -0,0 +1,20 @@ +# Security Solution Lists common package + +The package contains common files for the Lists feature. + +`common` in the name highlights that this package is intended to combine any common entities related to Lists in this package. E.g. the other `kbn-securitysolution-list-*` packages +content should be moved here while `kbn-securitysolution-io-ts-list-types` package should be +gone eventually. + +## API folder + +`api` folder contains OpenAPI schemas for Security Solution Lists feature. There are automatically generated Zod schemas and TS types for each schemas located in corresponding +`*.gen.ts` files. + +**Please add any Lists feature related schemas to this package.** + +TS types and/or Zod schemas can be imported in a plugin or another package like + +```ts +import { CreateListRequestBody } from '@kbn/securitysolution-lists-common/api'; +``` diff --git a/packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts new file mode 100644 index 00000000000000..22c4a1c47bb8ab --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/create_list/create_list.gen.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Create list API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { + ListId, + ListName, + ListDescription, + ListType, + ListMetadata, +} from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type CreateListRequestBody = z.infer; +export const CreateListRequestBody = z.object({ + id: ListId.optional(), + name: ListName, + description: ListDescription, + type: ListType, + serializer: z.string().optional(), + deserializer: z.string().optional(), + meta: ListMetadata.optional(), + version: z.number().int().min(1).optional().default(1), +}); +export type CreateListRequestBodyInput = z.input; + +export type CreateListResponse = z.infer; +export const CreateListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml new file mode 100644 index 00000000000000..0cd635c46ff7f9 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/create_list/create_list.schema.yaml @@ -0,0 +1,82 @@ +openapi: 3.0.0 +info: + title: Create list API endpoint + version: '2023-10-31' +paths: + /api/lists: + post: + x-labels: [serverless, ess] + operationId: CreateList + x-codegen-enabled: true + summary: Creates a list + tags: + - List API + requestBody: + description: List's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + name: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListName' + description: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListDescription' + type: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListType' + serializer: + type: string + deserializer: + type: string + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListMetadata' + version: + type: integer + minimum: 1 + default: 1 + required: + - name + - description + - type + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 409: + description: List already exists response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts b/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts new file mode 100644 index 00000000000000..b2217f20164226 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.gen.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Create list DS API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +export type CreateListIndexResponse = z.infer; +export const CreateListIndexResponse = z.object({ + acknowledged: z.boolean(), +}); diff --git a/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml b/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml new file mode 100644 index 00000000000000..f42937a8885d24 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/create_list_index/create_list_index.schema.yaml @@ -0,0 +1,56 @@ +openapi: 3.0.0 +info: + title: Create list DS API endpoint + version: '2023-10-31' +paths: + /api/lists/index: + post: + x-labels: [serverless, ess] + operationId: CreateListIndex + x-codegen-enabled: true + summary: Creates necessary list data streams + tags: + - List API + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: [acknowledged] + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 409: + description: List data stream exists response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts new file mode 100644 index 00000000000000..94e1be21719210 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.gen.ts @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Create list item API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListItemId, ListId, ListItemValue, ListItemMetadata } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type CreateListItemRequestBody = z.infer; +export const CreateListItemRequestBody = z.object({ + id: ListItemId.optional(), + list_id: ListId, + value: ListItemValue, + meta: ListItemMetadata.optional(), + /** + * Determines when changes made by the request are made visible to search + */ + refresh: z.enum(['true', 'false', 'wait_for']).optional(), +}); +export type CreateListItemRequestBodyInput = z.input; + +export type CreateListItemResponse = z.infer; +export const CreateListItemResponse = ListItem; diff --git a/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml new file mode 100644 index 00000000000000..ca75b8555b9c45 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/create_list_item/create_list_item.schema.yaml @@ -0,0 +1,78 @@ +openapi: 3.0.0 +info: + title: Create list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + post: + x-labels: [serverless, ess] + operationId: CreateListItem + x-codegen-enabled: true + summary: Creates a list item + tags: + - List item API + requestBody: + description: List item's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemId' + list_id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + value: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemValue' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemMetadata' + refresh: + type: string + enum: + - 'true' + - 'false' + - wait_for + description: Determines when changes made by the request are made visible to search + required: + - list_id + - value + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 409: + description: List item already exists response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.ts new file mode 100644 index 00000000000000..fe058928eca0b8 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.gen.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 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Delete list API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; +import { BooleanFromString } from '@kbn/zod-helpers'; + +import { ListId } from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type DeleteListRequestQuery = z.infer; +export const DeleteListRequestQuery = z.object({ + /** + * List's `id` value + */ + id: ListId, + deleteReferences: BooleanFromString.optional().default(false), + ignoreReferences: BooleanFromString.optional().default(false), +}); +export type DeleteListRequestQueryInput = z.input; + +export type DeleteListResponse = z.infer; +export const DeleteListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml new file mode 100644 index 00000000000000..c116d43edd93a0 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/delete_list/delete_list.schema.yaml @@ -0,0 +1,71 @@ +openapi: 3.0.0 +info: + title: Delete list API endpoint + version: '2023-10-31' +paths: + /api/lists: + delete: + x-labels: [serverless, ess] + operationId: DeleteList + x-codegen-enabled: true + summary: Deletes a list + tags: + - List API + parameters: + - name: id + in: query + required: true + description: List's `id` value + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: deleteReferences + in: query + required: false + schema: + type: boolean + default: false + - name: ignoreReferences + in: query + required: false + schema: + type: boolean + default: false + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts b/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts new file mode 100644 index 00000000000000..3be609d0b8a920 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.gen.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Delete list DS API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +export type DeleteListIndexResponse = z.infer; +export const DeleteListIndexResponse = z.object({ + acknowledged: z.boolean(), +}); diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml b/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml new file mode 100644 index 00000000000000..c3b4969aa32830 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/delete_list_index/delete_list_index.schema.yaml @@ -0,0 +1,56 @@ +openapi: 3.0.0 +info: + title: Delete list DS API endpoint + version: '2023-10-31' +paths: + /api/lists/index: + delete: + x-labels: [serverless, ess] + operationId: DeleteListIndex + x-codegen-enabled: true + summary: Deletes list data streams + tags: + - List API + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: [acknowledged] + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List data stream not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.ts new file mode 100644 index 00000000000000..d94b2f18d6158b --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.gen.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 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Delete list item API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListId } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type DeleteListItemRequestQuery = z.infer; +export const DeleteListItemRequestQuery = z.object({ + /** + * Required if `list_id` and `value` are not specified + */ + id: ListId.optional(), + /** + * Required if `id` is not specified + */ + list_id: ListId.optional(), + /** + * Required if `id` is not specified + */ + value: z.string().optional(), + /** + * Determines when changes made by the request are made visible to search + */ + refresh: z.enum(['true', 'false', 'wait_for']).optional().default('false'), +}); +export type DeleteListItemRequestQueryInput = z.input; + +export type DeleteListItemResponse = z.infer; +export const DeleteListItemResponse = z.union([ListItem, z.array(ListItem)]); diff --git a/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml new file mode 100644 index 00000000000000..63938d313aea25 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/delete_list_item/delete_list_item.schema.yaml @@ -0,0 +1,83 @@ +openapi: 3.0.0 +info: + title: Delete list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + delete: + x-labels: [serverless, ess] + operationId: DeleteListItem + x-codegen-enabled: true + summary: Deletes a list item + tags: + - List item API + parameters: + - name: id + in: query + required: false + description: Required if `list_id` and `value` are not specified + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: list_id + in: query + required: false + description: Required if `id` is not specified + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: value + in: query + required: false + description: Required if `id` is not specified + schema: + type: string + - name: refresh + in: query + required: false + description: Determines when changes made by the request are made visible to search + schema: + type: string + enum: ['true', 'false', 'wait_for'] + default: 'false' + responses: + 200: + description: Successful response + content: + application/json: + schema: + oneOf: + - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + - type: array + items: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List item not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.gen.ts new file mode 100644 index 00000000000000..0e831e0887bd0d --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.gen.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Export list items API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListId } from '../model/list_common.gen'; + +export type ExportListItemsRequestQuery = z.infer; +export const ExportListItemsRequestQuery = z.object({ + /** + * List's id to export + */ + list_id: ListId, +}); +export type ExportListItemsRequestQueryInput = z.input; diff --git a/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.schema.yaml new file mode 100644 index 00000000000000..26708a18a899ad --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.schema.yaml @@ -0,0 +1,61 @@ +openapi: 3.0.0 +info: + title: Export list items API endpoint + version: '2023-10-31' +paths: + /api/lists/items/_export: + post: + operationId: ExportListItems + x-codegen-enabled: true + summary: Exports list items + description: Exports list item values from the specified list + tags: + - List items Import/Export API + parameters: + - name: list_id + in: query + required: true + description: List's id to export + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + responses: + 200: + description: Successful response + content: + application/ndjson: + schema: + type: string + format: binary + description: A `.txt` file containing list items from the specified list + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/find_list/find_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/find_list/find_list.gen.ts new file mode 100644 index 00000000000000..22bd50fcf0f351 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/find_list/find_list.gen.ts @@ -0,0 +1,70 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Find lists API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { NonEmptyString } from '@kbn/openapi-common/schemas/primitives.gen'; +import { List } from '../model/list_schemas.gen'; + +export type FindListsCursor = z.infer; +export const FindListsCursor = NonEmptyString; + +export type FindListsFilter = z.infer; +export const FindListsFilter = NonEmptyString; + +export type FindListsRequestQuery = z.infer; +export const FindListsRequestQuery = z.object({ + /** + * The page number to return + */ + page: z.coerce.number().int().optional(), + /** + * The number of lists to return per page + */ + per_page: z.coerce.number().int().optional(), + /** + * Determines which field is used to sort the results + */ + sort_field: NonEmptyString.optional(), + /** + * Determines the sort order, which can be `desc` or `asc` + */ + sort_order: z.enum(['desc', 'asc']).optional(), + /** + * Returns the list that come after the last list returned in the previous call +(use the cursor value returned in the previous call). This parameter uses +the `tie_breaker_id` field to ensure all lists are sorted and returned correctly. + + */ + cursor: FindListsCursor.optional(), + /** + * Filters the returned results according to the value of the specified field, +using the : syntax. + + */ + filter: FindListsFilter.optional(), +}); +export type FindListsRequestQueryInput = z.input; + +export type FindListsResponse = z.infer; +export const FindListsResponse = z.object({ + data: z.array(List), + page: z.number().int().min(0), + per_page: z.number().int().min(0), + total: z.number().int().min(0), + cursor: FindListsCursor, +}); diff --git a/packages/kbn-securitysolution-lists-common/api/find_list/find_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/find_list/find_list.schema.yaml new file mode 100644 index 00000000000000..7fa5f1ac581ac7 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/find_list/find_list.schema.yaml @@ -0,0 +1,119 @@ +openapi: 3.0.0 +info: + title: Find lists API endpoint + version: '2023-10-31' +paths: + /api/lists/_find: + get: + x-labels: [serverless, ess] + operationId: FindLists + x-codegen-enabled: true + summary: Finds lists + tags: + - List API + parameters: + - name: page + in: query + required: false + description: The page number to return + schema: + type: integer + - name: per_page + in: query + required: false + description: The number of lists to return per page + schema: + type: integer + - name: sort_field + in: query + required: false + description: Determines which field is used to sort the results + schema: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + - name: sort_order + in: query + required: false + description: Determines the sort order, which can be `desc` or `asc` + schema: + type: string + enum: [desc, asc] + - name: cursor + in: query + required: false + description: | + Returns the list that come after the last list returned in the previous call + (use the cursor value returned in the previous call). This parameter uses + the `tie_breaker_id` field to ensure all lists are sorted and returned correctly. + schema: + $ref: '#/components/schemas/FindListsCursor' + - name: filter + in: query + required: false + description: | + Filters the returned results according to the value of the specified field, + using the : syntax. + schema: + $ref: '#/components/schemas/FindListsFilter' + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + page: + type: integer + minimum: 0 + per_page: + type: integer + minimum: 0 + total: + type: integer + minimum: 0 + cursor: + $ref: '#/components/schemas/FindListsCursor' + required: + - data + - page + - per_page + - total + - cursor + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + FindListsCursor: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + FindListsFilter: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' diff --git a/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.gen.ts new file mode 100644 index 00000000000000..ef23adf7a7dcdc --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.gen.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Find list items API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { NonEmptyString } from '@kbn/openapi-common/schemas/primitives.gen'; +import { ListId } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type FindListItemsCursor = z.infer; +export const FindListItemsCursor = NonEmptyString; + +export type FindListItemsFilter = z.infer; +export const FindListItemsFilter = NonEmptyString; + +export type FindListItemsRequestQuery = z.infer; +export const FindListItemsRequestQuery = z.object({ + /** + * List's ide + */ + list_id: ListId, + /** + * The page number to return + */ + page: z.coerce.number().int().optional(), + /** + * The number of list items to return per page + */ + per_page: z.coerce.number().int().optional(), + /** + * Determines which field is used to sort the results + */ + sort_field: NonEmptyString.optional(), + /** + * Determines the sort order, which can be `desc` or `asc` + */ + sort_order: z.enum(['desc', 'asc']).optional(), + /** + * Returns the list that come after the last list returned in the previous call +(use the cursor value returned in the previous call). This parameter uses +the `tie_breaker_id` field to ensure all lists are sorted and returned correctly. + + */ + cursor: FindListItemsCursor.optional(), + /** + * Filters the returned results according to the value of the specified field, +using the : syntax. + + */ + filter: FindListItemsFilter.optional(), +}); +export type FindListItemsRequestQueryInput = z.input; + +export type FindListItemsResponse = z.infer; +export const FindListItemsResponse = z.object({ + data: z.array(ListItem), + page: z.number().int().min(0), + per_page: z.number().int().min(0), + total: z.number().int().min(0), + cursor: FindListItemsCursor, +}); diff --git a/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.schema.yaml new file mode 100644 index 00000000000000..92dbc361b7ad2b --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.schema.yaml @@ -0,0 +1,125 @@ +openapi: 3.0.0 +info: + title: Find list items API endpoint + version: '2023-10-31' +paths: + /api/lists/_find: + get: + x-labels: [serverless, ess] + operationId: FindListItems + x-codegen-enabled: true + summary: Finds list items + tags: + - List API + parameters: + - name: list_id + in: query + required: true + description: List's ide + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: page + in: query + required: false + description: The page number to return + schema: + type: integer + - name: per_page + in: query + required: false + description: The number of list items to return per page + schema: + type: integer + - name: sort_field + in: query + required: false + description: Determines which field is used to sort the results + schema: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + - name: sort_order + in: query + required: false + description: Determines the sort order, which can be `desc` or `asc` + schema: + type: string + enum: [desc, asc] + - name: cursor + in: query + required: false + description: | + Returns the list that come after the last list returned in the previous call + (use the cursor value returned in the previous call). This parameter uses + the `tie_breaker_id` field to ensure all lists are sorted and returned correctly. + schema: + $ref: '#/components/schemas/FindListItemsCursor' + - name: filter + in: query + required: false + description: | + Filters the returned results according to the value of the specified field, + using the : syntax. + schema: + $ref: '#/components/schemas/FindListItemsFilter' + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + page: + type: integer + minimum: 0 + per_page: + type: integer + minimum: 0 + total: + type: integer + minimum: 0 + cursor: + $ref: '#/components/schemas/FindListItemsCursor' + required: + - data + - page + - per_page + - total + - cursor + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + FindListItemsCursor: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + FindListItemsFilter: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' diff --git a/packages/kbn-securitysolution-lists-common/api/get_list_privileges/get_list_privileges.gen.ts b/packages/kbn-securitysolution-lists-common/api/get_list_privileges/get_list_privileges.gen.ts new file mode 100644 index 00000000000000..3fe6348242822e --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/get_list_privileges/get_list_privileges.gen.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Get list privileges API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +export type ListPrivileges = z.infer; +export const ListPrivileges = z.object({ + username: z.string(), + has_all_requested: z.boolean(), + cluster: z.object({}).catchall(z.boolean()), + index: z.object({}).catchall(z.object({}).catchall(z.boolean())), + application: z.object({}).catchall(z.boolean()), +}); + +export type ListItemPrivileges = z.infer; +export const ListItemPrivileges = z.object({ + username: z.string(), + has_all_requested: z.boolean(), + cluster: z.object({}).catchall(z.boolean()), + index: z.object({}).catchall(z.object({}).catchall(z.boolean())), + application: z.object({}).catchall(z.boolean()), +}); + +export type GetListPrivilegesResponse = z.infer; +export const GetListPrivilegesResponse = z.object({ + lists: ListPrivileges, + listItems: ListItemPrivileges, + is_authenticated: z.boolean(), +}); diff --git a/packages/kbn-securitysolution-lists-common/api/get_list_privileges/get_list_privileges.schema.yaml b/packages/kbn-securitysolution-lists-common/api/get_list_privileges/get_list_privileges.schema.yaml new file mode 100644 index 00000000000000..729da9b8f62a82 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/get_list_privileges/get_list_privileges.schema.yaml @@ -0,0 +1,115 @@ +openapi: 3.0.0 +info: + title: Get list privileges API endpoint + version: '2023-10-31' +paths: + /api/lists/privileges: + get: + x-labels: [serverless, ess] + operationId: GetListPrivileges + x-codegen-enabled: true + summary: Gets list privileges + tags: + - List API + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + lists: + $ref: '#/components/schemas/ListPrivileges' + listItems: + $ref: '#/components/schemas/ListItemPrivileges' + is_authenticated: + type: boolean + required: + - lists + - listItems + - is_authenticated + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + +components: + schemas: + ListPrivileges: + type: object + properties: + username: + type: string + has_all_requested: + type: boolean + cluster: + type: object + additionalProperties: + type: boolean + index: + type: object + additionalProperties: + type: object + additionalProperties: + type: boolean + application: + type: object + additionalProperties: + type: boolean + required: + - username + - has_all_requested + - cluster + - index + - application + + ListItemPrivileges: + type: object + properties: + username: + type: string + has_all_requested: + type: boolean + cluster: + type: object + additionalProperties: + type: boolean + index: + type: object + additionalProperties: + type: object + additionalProperties: + type: boolean + application: + type: object + additionalProperties: + type: boolean + required: + - username + - has_all_requested + - cluster + - index + - application diff --git a/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.gen.ts new file mode 100644 index 00000000000000..5748e6a78e2c00 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.gen.ts @@ -0,0 +1,49 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Import list items API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListId, ListType } from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type ImportListItemsRequestQuery = z.infer; +export const ImportListItemsRequestQuery = z.object({ + /** + * List's id. + +Required when importing to an existing list. + + */ + list_id: ListId.optional(), + /** + * Type of the importing list. + +Required when importing a new list that is `list_id` is not specified. + + */ + type: ListType.optional(), + serializer: z.string().optional(), + deserializer: z.string().optional(), + /** + * Determines when changes made by the request are made visible to search + */ + refresh: z.enum(['true', 'false', 'wait_for']).optional(), +}); +export type ImportListItemsRequestQueryInput = z.input; + +export type ImportListItemsResponse = z.infer; +export const ImportListItemsResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.schema.yaml new file mode 100644 index 00000000000000..561d52587aad23 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.schema.yaml @@ -0,0 +1,102 @@ +openapi: 3.0.0 +info: + title: Import list items API endpoint + version: '2023-10-31' +paths: + /api/lists/items/_import: + post: + operationId: ImportListItems + x-codegen-enabled: true + summary: Imports list items + description: | + Imports a list of items from a `.txt` or `.csv` file. The maximum file size is 9 million bytes. + + You can import items to a new or existing list. + tags: + - List items Import/Export API + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + description: A `.txt` or `.csv` file containing newline separated list items + parameters: + - name: list_id + in: query + required: false + description: | + List's id. + + Required when importing to an existing list. + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: type + in: query + required: false + description: | + Type of the importing list. + + Required when importing a new list that is `list_id` is not specified. + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListType' + - name: serializer + in: query + required: false + schema: + type: string + - name: deserializer + in: query + required: false + schema: + type: string + - name: refresh + in: query + required: false + description: Determines when changes made by the request are made visible to search + schema: + type: string + enum: ['true', 'false', 'wait_for'] + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 409: + description: List with specified list_id does not exist response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/index.ts b/packages/kbn-securitysolution-lists-common/api/index.ts new file mode 100644 index 00000000000000..7b1fb1508653db --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 * from './model/list_common.gen'; +export * from './model/list_schemas.gen'; +export * from './create_list_index/create_list_index.gen'; +export * from './create_list_item/create_list_item.gen'; +export * from './create_list/create_list.gen'; +export * from './delete_list_index/delete_list_index.gen'; +export * from './delete_list_item/delete_list_item.gen'; +export * from './delete_list/delete_list.gen'; +export * from './find_list_item/find_list_item.gen'; +export * from './find_list/find_list.gen'; +export * from './export_list_item/export_list_item.gen'; +export * from './import_list_item/import_list_item.gen'; +export * from './patch_list_item/patch_list_item.gen'; +export * from './patch_list/patch_list.gen'; +export * from './read_list_index/read_list_index.gen'; +export * from './read_list_item/read_list_item.gen'; +export * from './read_list/read_list.gen'; +export * from './update_list_item/update_list_item.gen'; +export * from './update_list/update_list.gen'; diff --git a/packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts b/packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts new file mode 100644 index 00000000000000..f4a6a007fed9bf --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/model/list_common.gen.ts @@ -0,0 +1,73 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Common List Attributes + * version: not applicable + */ + +import { z } from 'zod'; + +import { NonEmptyString } from '@kbn/openapi-common/schemas/primitives.gen'; + +export type ListId = z.infer; +export const ListId = NonEmptyString; + +export type ListType = z.infer; +export const ListType = z.enum([ + 'binary', + 'boolean', + 'byte', + 'date', + 'date_nanos', + 'date_range', + 'double', + 'double_range', + 'float', + 'float_range', + 'geo_point', + 'geo_shape', + 'half_float', + 'integer', + 'integer_range', + 'ip', + 'ip_range', + 'keyword', + 'long', + 'long_range', + 'shape', + 'short', + 'text', +]); +export type ListTypeEnum = typeof ListType.enum; +export const ListTypeEnum = ListType.enum; + +export type ListName = z.infer; +export const ListName = NonEmptyString; + +export type ListDescription = z.infer; +export const ListDescription = NonEmptyString; + +export type ListMetadata = z.infer; +export const ListMetadata = z.object({}).catchall(z.unknown()); + +export type ListItemId = z.infer; +export const ListItemId = NonEmptyString; + +export type ListItemValue = z.infer; +export const ListItemValue = NonEmptyString; + +export type ListItemDescription = z.infer; +export const ListItemDescription = NonEmptyString; + +export type ListItemMetadata = z.infer; +export const ListItemMetadata = z.object({}).catchall(z.unknown()); diff --git a/packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml b/packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml new file mode 100644 index 00000000000000..6fb160105bb5a0 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/model/list_common.schema.yaml @@ -0,0 +1,59 @@ +openapi: 3.0.0 +info: + title: Common List Attributes + version: 'not applicable' +paths: {} +components: + schemas: + ListId: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListType: + type: string + enum: + - binary + - boolean + - byte + - date + - date_nanos + - date_range + - double + - double_range + - float + - float_range + - geo_point + - geo_shape + - half_float + - integer + - integer_range + - ip + - ip_range + - keyword + - long + - long_range + - shape + - short + - text + + ListName: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListDescription: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListMetadata: + type: object + additionalProperties: true + + ListItemId: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListItemValue: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListItemDescription: + $ref: '../../../kbn-openapi-common/schemas/primitives.schema.yaml#/components/schemas/NonEmptyString' + + ListItemMetadata: + type: object + additionalProperties: true diff --git a/packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts b/packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts new file mode 100644 index 00000000000000..c70278df938ce5 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/model/list_schemas.gen.ts @@ -0,0 +1,67 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: List Schemas + * version: not applicable + */ + +import { z } from 'zod'; + +import { + ListId, + ListType, + ListName, + ListDescription, + ListMetadata, + ListItemId, + ListItemValue, + ListItemMetadata, +} from './list_common.gen'; + +export type List = z.infer; +export const List = z.object({ + id: ListId, + type: ListType, + name: ListName, + description: ListDescription, + serializer: z.string().optional(), + deserializer: z.string().optional(), + immutable: z.boolean(), + meta: ListMetadata.optional(), + '@timestamp': z.string().datetime().optional(), + version: z.number().int().min(1), + _version: z.string().optional(), + tie_breaker_id: z.string(), + created_at: z.string().datetime(), + created_by: z.string(), + updated_at: z.string().datetime(), + updated_by: z.string(), +}); + +export type ListItem = z.infer; +export const ListItem = z.object({ + id: ListItemId, + type: ListType, + list_id: ListId, + value: ListItemValue, + serializer: z.string().optional(), + deserializer: z.string().optional(), + meta: ListItemMetadata.optional(), + '@timestamp': z.string().datetime().optional(), + _version: z.string().optional(), + tie_breaker_id: z.string(), + created_at: z.string().datetime(), + created_by: z.string(), + updated_at: z.string().datetime(), + updated_by: z.string(), +}); diff --git a/packages/kbn-securitysolution-lists-common/api/model/list_schemas.schema.yaml b/packages/kbn-securitysolution-lists-common/api/model/list_schemas.schema.yaml new file mode 100644 index 00000000000000..838dc5e4edea0b --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/model/list_schemas.schema.yaml @@ -0,0 +1,103 @@ +openapi: 3.0.0 +info: + title: List Schemas + version: 'not applicable' +paths: {} +components: + schemas: + List: + type: object + properties: + id: + $ref: './list_common.schema.yaml#/components/schemas/ListId' + type: + $ref: './list_common.schema.yaml#/components/schemas/ListType' + name: + $ref: './list_common.schema.yaml#/components/schemas/ListName' + description: + $ref: './list_common.schema.yaml#/components/schemas/ListDescription' + serializer: + type: string + deserializer: + type: string + immutable: + type: boolean + meta: + $ref: './list_common.schema.yaml#/components/schemas/ListMetadata' + '@timestamp': + type: string + format: date-time + version: + type: integer + minimum: 1 + _version: + type: string + tie_breaker_id: + type: string + created_at: + type: string + format: date-time + created_by: + type: string + updated_at: + type: string + format: date-time + updated_by: + type: string + required: + - id + - type + - name + - description + - immutable + - version + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + + ListItem: + type: object + properties: + id: + $ref: './list_common.schema.yaml#/components/schemas/ListItemId' + type: + $ref: './list_common.schema.yaml#/components/schemas/ListType' + list_id: + $ref: './list_common.schema.yaml#/components/schemas/ListId' + value: + $ref: './list_common.schema.yaml#/components/schemas/ListItemValue' + serializer: + type: string + deserializer: + type: string + meta: + $ref: './list_common.schema.yaml#/components/schemas/ListItemMetadata' + '@timestamp': + type: string + format: date-time + _version: + type: string + tie_breaker_id: + type: string + created_at: + type: string + format: date-time + created_by: + type: string + updated_at: + type: string + format: date-time + updated_by: + type: string + required: + - id + - type + - list_id + - value + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by diff --git a/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts new file mode 100644 index 00000000000000..47eeb87d0f5d47 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.gen.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Patch list API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListId, ListName, ListDescription, ListMetadata } from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type PatchListRequestBody = z.infer; +export const PatchListRequestBody = z.object({ + id: ListId, + name: ListName.optional(), + description: ListDescription.optional(), + meta: ListMetadata.optional(), + version: z.number().int().min(1).optional(), + _version: z.string().optional(), +}); +export type PatchListRequestBodyInput = z.input; + +export type PatchListResponse = z.infer; +export const PatchListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml new file mode 100644 index 00000000000000..cae09887db3120 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/patch_list/patch_list.schema.yaml @@ -0,0 +1,75 @@ +openapi: 3.0.0 +info: + title: Patch list API endpoint + version: '2023-10-31' +paths: + /api/lists: + patch: + x-labels: [serverless, ess] + operationId: PatchList + x-codegen-enabled: true + summary: Patches a list + tags: + - List API + requestBody: + description: List's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + name: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListName' + description: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListDescription' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListMetadata' + version: + type: integer + minimum: 1 + _version: + type: string + required: + - id + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts new file mode 100644 index 00000000000000..ce29d68bed7a78 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.gen.ts @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Patch list item API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListItemId, ListItemValue, ListItemMetadata } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type PatchListItemRequestBody = z.infer; +export const PatchListItemRequestBody = z.object({ + id: ListItemId, + value: ListItemValue.optional(), + meta: ListItemMetadata.optional(), + _version: z.string().optional(), + /** + * Determines when changes made by the request are made visible to search + */ + refresh: z.enum(['true', 'false', 'wait_for']).optional(), +}); +export type PatchListItemRequestBodyInput = z.input; + +export type PatchListItemResponse = z.infer; +export const PatchListItemResponse = ListItem; diff --git a/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml new file mode 100644 index 00000000000000..36ca55c7ae0659 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/patch_list_item/patch_list_item.schema.yaml @@ -0,0 +1,77 @@ +openapi: 3.0.0 +info: + title: Patch list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + patch: + x-labels: [serverless, ess] + operationId: PatchListItem + x-codegen-enabled: true + summary: Patches a list item + tags: + - List item API + requestBody: + description: List item's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemId' + value: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemValue' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemMetadata' + _version: + type: string + refresh: + type: string + enum: + - 'true' + - 'false' + - wait_for + description: Determines when changes made by the request are made visible to search + required: + - id + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List item not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts new file mode 100644 index 00000000000000..2ae0eb6f6c91b3 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/read_list/read_list.gen.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Get list API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListId } from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type GetListRequestQuery = z.infer; +export const GetListRequestQuery = z.object({ + /** + * List's `id` value + */ + id: ListId, +}); +export type GetListRequestQueryInput = z.input; + +export type GetListResponse = z.infer; +export const GetListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml new file mode 100644 index 00000000000000..4a2ae5d2cd42c1 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/read_list/read_list.schema.yaml @@ -0,0 +1,59 @@ +openapi: 3.0.0 +info: + title: Get list API endpoint + version: '2023-10-31' +paths: + /api/lists: + get: + x-labels: [serverless, ess] + operationId: GetList + x-codegen-enabled: true + summary: Retrieves a list using its id field + tags: + - List API + parameters: + - name: id + in: query + required: true + description: List's `id` value + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts b/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts new file mode 100644 index 00000000000000..c25105f0386366 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.gen.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Get list DS existence status API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +export type GetListIndexResponse = z.infer; +export const GetListIndexResponse = z.object({ + list_index: z.boolean(), + list_item_index: z.boolean(), +}); diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml b/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml new file mode 100644 index 00000000000000..accef8b58411e3 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/read_list_index/read_list_index.schema.yaml @@ -0,0 +1,58 @@ +openapi: 3.0.0 +info: + title: Get list DS existence status API endpoint + version: '2023-10-31' +paths: + /api/lists/index: + get: + x-labels: [serverless, ess] + operationId: GetListIndex + x-codegen-enabled: true + summary: Get list data stream existence status + tags: + - List API + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + list_index: + type: boolean + list_item_index: + type: boolean + required: [list_index, list_item_index] + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List data stream(s) not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.ts new file mode 100644 index 00000000000000..e9f5b9eef9cf86 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.gen.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 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Get list item API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListId } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type GetListItemRequestQuery = z.infer; +export const GetListItemRequestQuery = z.object({ + /** + * Required if `list_id` and `value` are not specified + */ + id: ListId.optional(), + /** + * Required if `id` is not specified + */ + list_id: ListId.optional(), + /** + * Required if `id` is not specified + */ + value: z.string().optional(), +}); +export type GetListItemRequestQueryInput = z.input; + +export type GetListItemResponse = z.infer; +export const GetListItemResponse = z.union([ListItem, z.array(ListItem)]); diff --git a/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml new file mode 100644 index 00000000000000..3a651617163aa1 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/read_list_item/read_list_item.schema.yaml @@ -0,0 +1,75 @@ +openapi: 3.0.0 +info: + title: Get list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + get: + x-labels: [serverless, ess] + operationId: GetListItem + x-codegen-enabled: true + summary: Gets a list item + tags: + - List item API + parameters: + - name: id + in: query + required: false + description: Required if `list_id` and `value` are not specified + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: list_id + in: query + required: false + description: Required if `id` is not specified + schema: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + - name: value + in: query + required: false + description: Required if `id` is not specified + schema: + type: string + responses: + 200: + description: Successful response + content: + application/json: + schema: + oneOf: + - $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + - type: array + items: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List item not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts b/packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts new file mode 100644 index 00000000000000..833239a7eb82bf --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/update_list/update_list.gen.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Update list API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListId, ListName, ListDescription, ListMetadata } from '../model/list_common.gen'; +import { List } from '../model/list_schemas.gen'; + +export type UpdateListRequestBody = z.infer; +export const UpdateListRequestBody = z.object({ + id: ListId, + name: ListName, + description: ListDescription, + meta: ListMetadata.optional(), + version: z.number().int().min(1).optional(), + _version: z.string().optional(), +}); +export type UpdateListRequestBodyInput = z.input; + +export type UpdateListResponse = z.infer; +export const UpdateListResponse = List; diff --git a/packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml b/packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml new file mode 100644 index 00000000000000..d25b21157c7252 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/update_list/update_list.schema.yaml @@ -0,0 +1,77 @@ +openapi: 3.0.0 +info: + title: Update list API endpoint + version: '2023-10-31' +paths: + /api/lists: + put: + x-labels: [serverless, ess] + operationId: UpdateList + x-codegen-enabled: true + summary: Updates a list + tags: + - List API + requestBody: + description: List's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListId' + name: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListName' + description: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListDescription' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListMetadata' + version: + type: integer + minimum: 1 + _version: + type: string + required: + - id + - name + - description + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/List' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts b/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts new file mode 100644 index 00000000000000..069c101beaaf44 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.gen.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Update list item API endpoint + * version: 2023-10-31 + */ + +import { z } from 'zod'; + +import { ListItemId, ListItemValue, ListItemMetadata } from '../model/list_common.gen'; +import { ListItem } from '../model/list_schemas.gen'; + +export type UpdateListItemRequestBody = z.infer; +export const UpdateListItemRequestBody = z.object({ + id: ListItemId, + value: ListItemValue, + meta: ListItemMetadata.optional(), + _version: z.string().optional(), +}); +export type UpdateListItemRequestBodyInput = z.input; + +export type UpdateListItemResponse = z.infer; +export const UpdateListItemResponse = ListItem; diff --git a/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml new file mode 100644 index 00000000000000..21df82f4ba40a8 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/api/update_list_item/update_list_item.schema.yaml @@ -0,0 +1,71 @@ +openapi: 3.0.0 +info: + title: Update list item API endpoint + version: '2023-10-31' +paths: + /api/lists/items: + put: + x-labels: [serverless, ess] + operationId: UpdateListItem + x-codegen-enabled: true + summary: Updates a list item + tags: + - List item API + requestBody: + description: List item's properties + required: true + content: + application/json: + schema: + type: object + properties: + id: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemId' + value: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemValue' + meta: + $ref: '../model/list_common.schema.yaml#/components/schemas/ListItemMetadata' + _version: + type: string + required: + - id + - value + responses: + 200: + description: Successful response + content: + application/json: + schema: + $ref: '../model/list_schemas.schema.yaml#/components/schemas/ListItem' + 400: + description: Invalid input data response + content: + application/json: + schema: + oneOf: + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 401: + description: Unsuccessful authentication response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 403: + description: Not enough privileges response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + 404: + description: List item not found response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + 500: + description: Internal server error response + content: + application/json: + schema: + $ref: '../../../kbn-openapi-common/schemas/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/packages/kbn-securitysolution-lists-common/kibana.jsonc b/packages/kbn-securitysolution-lists-common/kibana.jsonc new file mode 100644 index 00000000000000..614314f10e8b41 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/securitysolution-lists-common", + "owner": "@elastic/security-detection-engine" +} diff --git a/packages/kbn-securitysolution-lists-common/package.json b/packages/kbn-securitysolution-lists-common/package.json new file mode 100644 index 00000000000000..298f0e47bb10f6 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/package.json @@ -0,0 +1,10 @@ +{ + "description": "Security Solution Lists common package", + "license": "SSPL-1.0 OR Elastic License 2.0", + "name": "@kbn/securitysolution-lists-common", + "private": true, + "version": "1.0.0", + "scripts": { + "openapi:generate": "node scripts/openapi_generate" + } +} diff --git a/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js b/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js new file mode 100644 index 00000000000000..8580994b16859c --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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. + */ + +require('../../../src/setup_node_env'); +const { resolve } = require('path'); +const { generate } = require('@kbn/openapi-generator'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await generate({ + title: 'OpenAPI Lists API Schemas', + rootDir: ROOT, + sourceGlob: './**/*.schema.yaml', + templateName: 'zod_operation_schema', + }); +})(); diff --git a/packages/kbn-securitysolution-lists-common/tsconfig.json b/packages/kbn-securitysolution-lists-common/tsconfig.json new file mode 100644 index 00000000000000..b6a14b40363c7a --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "exclude": ["target/**/*"], + "extends": "../../tsconfig.base.json", + "include": ["**/*.ts"], + "kbn_references": ["@kbn/zod-helpers", "@kbn/openapi-common"] +} diff --git a/packages/kbn-zod-helpers/index.ts b/packages/kbn-zod-helpers/index.ts index d8a62f58686b2d..e3b0f4e35a19d3 100644 --- a/packages/kbn-zod-helpers/index.ts +++ b/packages/kbn-zod-helpers/index.ts @@ -14,3 +14,4 @@ export * from './src/is_valid_date_math'; export * from './src/required_optional'; export * from './src/safe_parse_result'; export * from './src/stringify_zod_error'; +export * from './src/build_route_validation_with_zod'; diff --git a/packages/kbn-zod-helpers/src/build_route_validation_with_zod.ts b/packages/kbn-zod-helpers/src/build_route_validation_with_zod.ts new file mode 100644 index 00000000000000..a72eb96d3b9684 --- /dev/null +++ b/packages/kbn-zod-helpers/src/build_route_validation_with_zod.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { TypeOf, ZodType } from 'zod'; +import type { RouteValidationFunction, RouteValidationResultFactory } from '@kbn/core/server'; +import { stringifyZodError } from './stringify_zod_error'; + +/** + * Zod validation factory for Kibana route's request validation. + * It allows to pass a Zod schema for parameters, query and/or body validation. + * + * Example: + * + * ```ts + * router.versioned + * .post({ + * access: 'public', + * path: MY_URL, + * }) + * .addVersion( + * { + * version: 'my-version', + * validate: { + * request: { + * params: buildRouteValidationWithZod(MyRequestParamsZodSchema), + * query: buildRouteValidationWithZod(MyRequestQueryZodSchema), + * body: buildRouteValidationWithZod(MyRequestBodyZodSchema), + * }, + * }, + * }, + * ``` + */ +export function buildRouteValidationWithZod>( + schema: ZodSchema +): RouteValidationFunction { + return (inputValue: unknown, validationResult: RouteValidationResultFactory) => { + const decoded = schema.safeParse(inputValue); + + return decoded.success + ? validationResult.ok(decoded.data) + : validationResult.badRequest(stringifyZodError(decoded.error)); + }; +} diff --git a/packages/kbn-zod-helpers/tsconfig.json b/packages/kbn-zod-helpers/tsconfig.json index 0b3850da21158a..fbe3b91a894931 100644 --- a/packages/kbn-zod-helpers/tsconfig.json +++ b/packages/kbn-zod-helpers/tsconfig.json @@ -6,7 +6,5 @@ "exclude": ["target/**/*"], "extends": "../../tsconfig.base.json", "include": ["**/*.ts"], - "kbn_references": [ - "@kbn/datemath", - ] + "kbn_references": ["@kbn/datemath", "@kbn/core"] } diff --git a/tsconfig.base.json b/tsconfig.base.json index bd6380bf501c43..ea18fe456af854 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1238,6 +1238,8 @@ "@kbn/open-telemetry-instrumented-plugin/*": ["test/common/plugins/otel_metrics/*"], "@kbn/openapi-bundler": ["packages/kbn-openapi-bundler"], "@kbn/openapi-bundler/*": ["packages/kbn-openapi-bundler/*"], + "@kbn/openapi-common": ["packages/kbn-openapi-common"], + "@kbn/openapi-common/*": ["packages/kbn-openapi-common/*"], "@kbn/openapi-generator": ["packages/kbn-openapi-generator"], "@kbn/openapi-generator/*": ["packages/kbn-openapi-generator/*"], "@kbn/optimizer": ["packages/kbn-optimizer"], @@ -1498,6 +1500,8 @@ "@kbn/securitysolution-list-hooks/*": ["packages/kbn-securitysolution-list-hooks/*"], "@kbn/securitysolution-list-utils": ["packages/kbn-securitysolution-list-utils"], "@kbn/securitysolution-list-utils/*": ["packages/kbn-securitysolution-list-utils/*"], + "@kbn/securitysolution-lists-common": ["packages/kbn-securitysolution-lists-common"], + "@kbn/securitysolution-lists-common/*": ["packages/kbn-securitysolution-lists-common/*"], "@kbn/securitysolution-rules": ["packages/kbn-securitysolution-rules"], "@kbn/securitysolution-rules/*": ["packages/kbn-securitysolution-rules/*"], "@kbn/securitysolution-t-grid": ["packages/kbn-securitysolution-t-grid"], diff --git a/x-pack/plugins/lists/common/api/index.ts b/x-pack/plugins/lists/common/api/index.ts index 1d76a041d28241..1cbbeba2190781 100644 --- a/x-pack/plugins/lists/common/api/index.ts +++ b/x-pack/plugins/lists/common/api/index.ts @@ -27,20 +27,4 @@ export * from './exceptions/summary_exception_list/summary_exception_list_route' export * from './exceptions/update_endpoint_list_item/update_endpoint_list_item_route'; export * from './exceptions/update_exception_list_item/update_exception_list_item_route'; export * from './exceptions/update_exception_list/update_exception_list_route'; -export * from './values/create_list_index/create_list_index_route'; -export * from './values/create_list_item/create_list_item_route'; -export * from './values/create_list/create_list_route'; -export * from './values/delete_list_index/delete_list_index_route'; -export * from './values/delete_list_item/delete_list_item_route'; -export * from './values/delete_list/delete_list_route'; -export * from './values/find_list_item/find_list_item_route'; -export * from './values/find_list/find_list_route'; export * from './values/find_lists_by_size/find_lists_by_size_route'; -export * from './values/import_list_item/import_list_item_route'; -export * from './values/patch_list_item/patch_list_item_route'; -export * from './values/patch_list/patch_list_route'; -export * from './values/read_list_index/read_list_index_route'; -export * from './values/read_list_item/read_list_item_route'; -export * from './values/read_list/read_list_route'; -export * from './values/update_list_item/update_list_item_route'; -export * from './values/update_list/update_list_route'; diff --git a/x-pack/plugins/lists/common/api/values/create_list/create_list_route.ts b/x-pack/plugins/lists/common/api/values/create_list/create_list_route.ts deleted file mode 100644 index 71dc2eecde8eaf..00000000000000 --- a/x-pack/plugins/lists/common/api/values/create_list/create_list_route.ts +++ /dev/null @@ -1,15 +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 { - CreateListSchemaDecoded, - createListSchema, - listSchema, -} from '@kbn/securitysolution-io-ts-list-types'; - -export { createListSchema as createListRequest, listSchema as createListResponse }; -export type { CreateListSchemaDecoded as CreateListRequestDecoded }; diff --git a/x-pack/plugins/lists/common/api/values/create_list_index/create_list_index_route.ts b/x-pack/plugins/lists/common/api/values/create_list_index/create_list_index_route.ts deleted file mode 100644 index 85e094b273e13e..00000000000000 --- a/x-pack/plugins/lists/common/api/values/create_list_index/create_list_index_route.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. - */ - -import { acknowledgeSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { acknowledgeSchema as createListIndexResponse }; diff --git a/x-pack/plugins/lists/common/api/values/create_list_item/create_list_item_route.ts b/x-pack/plugins/lists/common/api/values/create_list_item/create_list_item_route.ts deleted file mode 100644 index 70cef948d6cf1f..00000000000000 --- a/x-pack/plugins/lists/common/api/values/create_list_item/create_list_item_route.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. - */ - -import { createListItemSchema, listItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { createListItemSchema as createListItemRequest, listItemSchema as createListItemResponse }; diff --git a/x-pack/plugins/lists/common/api/values/delete_list/delete_list_route.ts b/x-pack/plugins/lists/common/api/values/delete_list/delete_list_route.ts deleted file mode 100644 index b360d3e5c6880a..00000000000000 --- a/x-pack/plugins/lists/common/api/values/delete_list/delete_list_route.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. - */ - -import { deleteListSchema, listSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { deleteListSchema as deleteListRequestQuery, listSchema as deleteListResponse }; diff --git a/x-pack/plugins/lists/common/api/values/delete_list_index/delete_list_index_route.ts b/x-pack/plugins/lists/common/api/values/delete_list_index/delete_list_index_route.ts deleted file mode 100644 index 2423ebd6bea606..00000000000000 --- a/x-pack/plugins/lists/common/api/values/delete_list_index/delete_list_index_route.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. - */ - -import { acknowledgeSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { acknowledgeSchema as deleteListIndexResponse }; diff --git a/x-pack/plugins/lists/common/api/values/delete_list_item/delete_list_item_route.ts b/x-pack/plugins/lists/common/api/values/delete_list_item/delete_list_item_route.ts deleted file mode 100644 index 418401d2b6c170..00000000000000 --- a/x-pack/plugins/lists/common/api/values/delete_list_item/delete_list_item_route.ts +++ /dev/null @@ -1,18 +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 { - deleteListItemSchema, - listItemArraySchema, - listItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; - -export { - deleteListItemSchema as deleteListItemRequestQuery, - listItemSchema as deleteListItemResponse, - listItemArraySchema as deleteListItemArrayResponse, -}; diff --git a/x-pack/plugins/lists/common/api/values/find_list/find_list_route.ts b/x-pack/plugins/lists/common/api/values/find_list/find_list_route.ts deleted file mode 100644 index 8c3301daed3c9e..00000000000000 --- a/x-pack/plugins/lists/common/api/values/find_list/find_list_route.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. - */ - -import { findListSchema, foundListSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { findListSchema as findListRequestQuery, foundListSchema as findListResponse }; diff --git a/x-pack/plugins/lists/common/api/values/find_list_item/find_list_item_route.ts b/x-pack/plugins/lists/common/api/values/find_list_item/find_list_item_route.ts deleted file mode 100644 index b9d4d93ccb340e..00000000000000 --- a/x-pack/plugins/lists/common/api/values/find_list_item/find_list_item_route.ts +++ /dev/null @@ -1,18 +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 { - FindListItemSchemaDecoded, - findListItemSchema, - foundListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; - -export { - findListItemSchema as findListItemRequestQuery, - foundListItemSchema as findListItemResponse, -}; -export type { FindListItemSchemaDecoded as FindListItemRequestQueryDecoded }; diff --git a/x-pack/plugins/lists/common/api/values/import_list_item/import_list_item_route.ts b/x-pack/plugins/lists/common/api/values/import_list_item/import_list_item_route.ts deleted file mode 100644 index 3ea57eda532fcf..00000000000000 --- a/x-pack/plugins/lists/common/api/values/import_list_item/import_list_item_route.ts +++ /dev/null @@ -1,13 +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 { importListItemQuerySchema, listSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { - importListItemQuerySchema as importListItemRequestQuery, - listSchema as importListItemResponse, -}; diff --git a/x-pack/plugins/lists/common/api/values/patch_list/patch_list_route.ts b/x-pack/plugins/lists/common/api/values/patch_list/patch_list_route.ts deleted file mode 100644 index 8821658c5b23a2..00000000000000 --- a/x-pack/plugins/lists/common/api/values/patch_list/patch_list_route.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. - */ - -import { listSchema, patchListSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { patchListSchema as patchListRequest, listSchema as patchListResponse }; diff --git a/x-pack/plugins/lists/common/api/values/patch_list_item/patch_list_item_route.ts b/x-pack/plugins/lists/common/api/values/patch_list_item/patch_list_item_route.ts deleted file mode 100644 index 12b4bd36e968e6..00000000000000 --- a/x-pack/plugins/lists/common/api/values/patch_list_item/patch_list_item_route.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. - */ - -import { listItemSchema, patchListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { patchListItemSchema as patchListItemRequest, listItemSchema as patchListItemResponse }; diff --git a/x-pack/plugins/lists/common/api/values/read_list/read_list_route.ts b/x-pack/plugins/lists/common/api/values/read_list/read_list_route.ts deleted file mode 100644 index be13d604f57c50..00000000000000 --- a/x-pack/plugins/lists/common/api/values/read_list/read_list_route.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. - */ - -import { listSchema, readListSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { readListSchema as readListRequestQuery, listSchema as readListResponse }; diff --git a/x-pack/plugins/lists/common/api/values/read_list_index/read_list_index_route.ts b/x-pack/plugins/lists/common/api/values/read_list_index/read_list_index_route.ts deleted file mode 100644 index 772d042b7e11cc..00000000000000 --- a/x-pack/plugins/lists/common/api/values/read_list_index/read_list_index_route.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. - */ - -import { listItemIndexExistSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { listItemIndexExistSchema as readListIndexResponse }; diff --git a/x-pack/plugins/lists/common/api/values/read_list_item/read_list_item_route.ts b/x-pack/plugins/lists/common/api/values/read_list_item/read_list_item_route.ts deleted file mode 100644 index 0b67159ceaf03f..00000000000000 --- a/x-pack/plugins/lists/common/api/values/read_list_item/read_list_item_route.ts +++ /dev/null @@ -1,18 +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 { - listItemArraySchema, - listItemSchema, - readListItemSchema, -} from '@kbn/securitysolution-io-ts-list-types'; - -export { - readListItemSchema as readListItemRequestQuery, - listItemSchema as readListItemResponse, - listItemArraySchema as readListItemArrayResponse, -}; diff --git a/x-pack/plugins/lists/common/api/values/update_list/update_list_route.ts b/x-pack/plugins/lists/common/api/values/update_list/update_list_route.ts deleted file mode 100644 index 801e9784ac80df..00000000000000 --- a/x-pack/plugins/lists/common/api/values/update_list/update_list_route.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. - */ - -import { listSchema, updateListSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { updateListSchema as updateListRequest, listSchema as updateListResponse }; diff --git a/x-pack/plugins/lists/common/api/values/update_list_item/update_list_item_route.ts b/x-pack/plugins/lists/common/api/values/update_list_item/update_list_item_route.ts deleted file mode 100644 index 9b512e61f464e1..00000000000000 --- a/x-pack/plugins/lists/common/api/values/update_list_item/update_list_item_route.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. - */ - -import { listItemSchema, updateListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -export { updateListItemSchema as updateListItemRequest, listItemSchema as updateListItemResponse }; diff --git a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts index 117659423103d0..57dae64930dc53 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_list_schema.mock.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { CreateListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import type { CreateListRequestBodyInput } from '@kbn/securitysolution-lists-common/api'; import { DESCRIPTION, LIST_ID, META, NAME, TYPE, VERSION } from '../../constants.mock'; -export const getCreateListSchemaMock = (): CreateListSchema => ({ +export const getCreateListSchemaMock = (): CreateListRequestBodyInput => ({ description: DESCRIPTION, deserializer: undefined, id: LIST_ID, @@ -23,7 +23,7 @@ export const getCreateListSchemaMock = (): CreateListSchema => ({ /** * Useful for end to end tests and other mechanisms which want to fill in the values */ -export const getCreateMinimalListSchemaMock = (): CreateListSchema => ({ +export const getCreateMinimalListSchemaMock = (): CreateListRequestBodyInput => ({ description: DESCRIPTION, id: LIST_ID, name: NAME, @@ -33,7 +33,7 @@ export const getCreateMinimalListSchemaMock = (): CreateListSchema => ({ /** * Useful for end to end tests and other mechanisms which want to fill in the values */ -export const getCreateMinimalListSchemaMockWithoutId = (): CreateListSchema => ({ +export const getCreateMinimalListSchemaMockWithoutId = (): CreateListRequestBodyInput => ({ description: DESCRIPTION, name: NAME, type: TYPE, diff --git a/x-pack/plugins/lists/common/schemas/request/update_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/update_list_schema.mock.ts index d38744a35a6cb9..564c79e67a2bbd 100644 --- a/x-pack/plugins/lists/common/schemas/request/update_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/update_list_schema.mock.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { UpdateListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import type { UpdateListRequestBody } from '@kbn/securitysolution-lists-common/api'; import { DESCRIPTION, LIST_ID, META, NAME, _VERSION } from '../../constants.mock'; -export const getUpdateListSchemaMock = (): UpdateListSchema => ({ +export const getUpdateListSchemaMock = (): UpdateListRequestBody => ({ _version: _VERSION, description: DESCRIPTION, id: LIST_ID, @@ -21,7 +21,7 @@ export const getUpdateListSchemaMock = (): UpdateListSchema => ({ * Useful for end to end tests and other mechanisms which want to fill in the values * after doing a get of the structure. */ -export const getUpdateMinimalListSchemaMock = (): UpdateListSchema => ({ +export const getUpdateMinimalListSchemaMock = (): UpdateListRequestBody => ({ description: DESCRIPTION, id: LIST_ID, name: NAME, diff --git a/x-pack/plugins/lists/server/routes/list/create_list_route.ts b/x-pack/plugins/lists/server/routes/list/create_list_route.ts index 063056461c20cb..3b0e80aa7ee7ed 100644 --- a/x-pack/plugins/lists/server/routes/list/create_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/create_list_route.ts @@ -5,17 +5,13 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { CreateListRequestBody, CreateListResponse } from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { - CreateListRequestDecoded, - createListRequest, - createListResponse, -} from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const createListRoute = (router: ListsPluginRouter): void => { @@ -31,9 +27,7 @@ export const createListRoute = (router: ListsPluginRouter): void => { { validate: { request: { - body: buildRouteValidation( - createListRequest - ), + body: buildRouteValidationWithZod(CreateListRequestBody), }, }, version: '2023-10-31', @@ -77,12 +71,8 @@ export const createListRoute = (router: ListsPluginRouter): void => { type, version, }); - const [validated, errors] = validate(list, createListResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + + return response.ok({ body: CreateListResponse.parse(list) }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/lists/server/routes/list/delete_list_route.ts b/x-pack/plugins/lists/server/routes/list/delete_list_route.ts index f2571cd44acf90..d28b777a2ba8e4 100644 --- a/x-pack/plugins/lists/server/routes/list/delete_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/delete_list_route.ts @@ -17,12 +17,13 @@ import { } from '@kbn/securitysolution-io-ts-list-types'; import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { LIST_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { DeleteListRequestQuery, DeleteListResponse } from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; import type { ExceptionListClient } from '../../services/exception_lists/exception_list_client'; import { escapeQuotes } from '../../services/utils/escape_query'; -import { deleteListRequestQuery, deleteListResponse } from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getExceptionListClient, getListClient } from '..'; export const deleteListRoute = (router: ListsPluginRouter): void => { @@ -38,7 +39,7 @@ export const deleteListRoute = (router: ListsPluginRouter): void => { { validate: { request: { - query: buildRouteValidation(deleteListRequestQuery), + query: buildRouteValidationWithZod(DeleteListRequestQuery), }, }, version: '2023-10-31', @@ -49,7 +50,6 @@ export const deleteListRoute = (router: ListsPluginRouter): void => { const lists = await getListClient(context); const exceptionLists = await getExceptionListClient(context); const { id, deleteReferences, ignoreReferences } = request.query; - let deleteExceptionItemResponses; // ignoreReferences=true maintains pre-7.11 behavior of deleting value list without performing any additional checks if (!ignoreReferences) { @@ -75,7 +75,7 @@ export const deleteListRoute = (router: ListsPluginRouter): void => { if (deleteReferences) { // Delete referenced exception list items // TODO: Create deleteListItems to delete in batch - deleteExceptionItemResponses = await Promise.all( + await Promise.all( referencedExceptionListItems.map(async (listItem) => { // Ensure only the single entry is deleted as there could be a separate value list referenced that is okay to keep // TODO: Add API to delete single entry const remainingEntries = listItem.entries.filter( @@ -122,16 +122,9 @@ export const deleteListRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(deleted, deleteListResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ - body: validated ?? { - deleteItemResponses: deleteExceptionItemResponses, - }, - }); - } + return response.ok({ + body: DeleteListResponse.parse(deleted), + }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/lists/server/routes/list/import_list_item_route.ts b/x-pack/plugins/lists/server/routes/list/import_list_item_route.ts index d9d1bc5af1e6eb..f3f52828f78728 100644 --- a/x-pack/plugins/lists/server/routes/list/import_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list/import_list_item_route.ts @@ -8,14 +8,17 @@ import { extname } from 'path'; import { schema } from '@kbn/config-schema'; -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { + ImportListItemsRequestQuery, + ImportListItemsResponse, +} from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; import { ConfigType } from '../../config'; -import { importListItemRequestQuery, importListItemResponse } from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { createStreamFromBuffer } from '../utils/create_stream_from_buffer'; import { getListClient } from '..'; @@ -43,7 +46,7 @@ export const importListItemRoute = (router: ListsPluginRouter, config: ConfigTyp validate: { request: { body: schema.buffer(), - query: buildRouteValidation(importListItemRequestQuery), + query: buildRouteValidationWithZod(ImportListItemsRequestQuery), }, }, version: '2023-10-31', @@ -119,12 +122,7 @@ export const importListItemRoute = (router: ListsPluginRouter, config: ConfigTyp version: 1, }); - const [validated, errors] = validate(list, importListItemResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: ImportListItemsResponse.parse(list) }); } else if (type != null) { const importedList = await lists.importListItemsToStream({ deserializer, @@ -142,12 +140,8 @@ export const importListItemRoute = (router: ListsPluginRouter, config: ConfigTyp statusCode: 400, }); } - const [validated, errors] = validate(importedList, importListItemResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + + return response.ok({ body: ImportListItemsResponse.parse(importedList) }); } else { return siemResponse.error({ body: 'Either type or list_id need to be defined in the query', diff --git a/x-pack/plugins/lists/server/routes/list/patch_list_route.ts b/x-pack/plugins/lists/server/routes/list/patch_list_route.ts index 336239854f70bb..fb14166d74f9c1 100644 --- a/x-pack/plugins/lists/server/routes/list/patch_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/patch_list_route.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { PatchListRequestBody, PatchListResponse } from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { patchListRequest, patchListResponse } from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const patchListRoute = (router: ListsPluginRouter): void => { @@ -27,7 +27,7 @@ export const patchListRoute = (router: ListsPluginRouter): void => { { validate: { request: { - body: buildRouteValidation(patchListRequest), + body: buildRouteValidationWithZod(PatchListRequestBody), }, }, version: '2023-10-31', @@ -54,12 +54,7 @@ export const patchListRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(list, patchListResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: PatchListResponse.parse(list) }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/lists/server/routes/list/read_list_route.ts b/x-pack/plugins/lists/server/routes/list/read_list_route.ts index ab403e933e53fd..e9af8cfc8f4ebe 100644 --- a/x-pack/plugins/lists/server/routes/list/read_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/read_list_route.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { GetListRequestQuery, GetListResponse } from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { readListRequestQuery, readListResponse } from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const readListRoute = (router: ListsPluginRouter): void => { @@ -27,7 +27,7 @@ export const readListRoute = (router: ListsPluginRouter): void => { { validate: { request: { - query: buildRouteValidation(readListRequestQuery), + query: buildRouteValidationWithZod(GetListRequestQuery), }, }, version: '2023-10-31', @@ -44,12 +44,7 @@ export const readListRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(list, readListResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: GetListResponse.parse(list) }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/lists/server/routes/list/update_list_route.ts b/x-pack/plugins/lists/server/routes/list/update_list_route.ts index 46b2d8e0588575..c20714b75e090c 100644 --- a/x-pack/plugins/lists/server/routes/list/update_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/update_list_route.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { UpdateListRequestBody, UpdateListResponse } from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { updateListRequest, updateListResponse } from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const updateListRoute = (router: ListsPluginRouter): void => { @@ -27,7 +27,7 @@ export const updateListRoute = (router: ListsPluginRouter): void => { { validate: { request: { - body: buildRouteValidation(updateListRequest), + body: buildRouteValidationWithZod(UpdateListRequestBody), }, }, version: '2023-10-31', @@ -54,12 +54,7 @@ export const updateListRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(list, updateListResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: UpdateListResponse.parse(list) }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts b/x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts index e3cab179c2f406..2f74871f23fc22 100644 --- a/x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts @@ -5,11 +5,10 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_INDEX } from '@kbn/securitysolution-list-constants'; +import { CreateListIndexResponse } from '@kbn/securitysolution-lists-common/api'; -import { createListIndexResponse } from '../../../common/api'; import type { ListsPluginRouter } from '../../types'; import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; @@ -64,12 +63,7 @@ export const createListIndexRoute = (router: ListsPluginRouter): void => { : lists.createListItemDataStream()); } - const [validated, errors] = validate({ acknowledged: true }, createListIndexResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: CreateListIndexResponse.parse({ acknowledged: true }) }); } catch (err) { const error = transformError(err); return siemResponse.error({ diff --git a/x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts b/x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts index a9683f4636151a..0814739ab11e71 100644 --- a/x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts @@ -5,13 +5,12 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_INDEX } from '@kbn/securitysolution-list-constants'; +import { DeleteListIndexResponse } from '@kbn/securitysolution-lists-common/api'; import { ListClient } from '../../services/lists/list_client'; import type { ListsPluginRouter } from '../../types'; -import { deleteListIndexResponse } from '../../../common/api'; import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; @@ -83,12 +82,7 @@ export const deleteListIndexRoute = (router: ListsPluginRouter): void => { await deleteIndexTemplates(lists); - const [validated, errors] = validate({ acknowledged: true }, deleteListIndexResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: DeleteListIndexResponse.parse({ acknowledged: true }) }); } catch (err) { const error = transformError(err); return siemResponse.error({ diff --git a/x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts index 1d43d4fd8c181d..af9c40117f9c64 100644 --- a/x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts @@ -9,10 +9,11 @@ import { Stream } from 'stream'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { ExportListItemsRequestQuery } from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { exportListItemRequestQuery } from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const exportListItemRoute = (router: ListsPluginRouter): void => { @@ -28,7 +29,7 @@ export const exportListItemRoute = (router: ListsPluginRouter): void => { { validate: { request: { - query: buildRouteValidation(exportListItemRequestQuery), + query: buildRouteValidationWithZod(ExportListItemsRequestQuery), }, }, version: '2023-10-31', diff --git a/x-pack/plugins/lists/server/routes/list_index/find_list_route.ts b/x-pack/plugins/lists/server/routes/list_index/find_list_route.ts index 9b492006e0605b..157b11e3832eb0 100644 --- a/x-pack/plugins/lists/server/routes/list_index/find_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/find_list_route.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { FindListsRequestQuery, FindListsResponse } from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; import { decodeCursor } from '../../services/utils'; -import { findListRequestQuery, findListResponse } from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse, getListClient } from '../utils'; +import { buildSiemResponse, getListClient } from '../utils'; export const findListRoute = (router: ListsPluginRouter): void => { router.versioned @@ -27,7 +27,7 @@ export const findListRoute = (router: ListsPluginRouter): void => { { validate: { request: { - query: buildRouteValidation(findListRequestQuery), + query: buildRouteValidationWithZod(FindListsRequestQuery), }, }, version: '2023-10-31', @@ -74,12 +74,8 @@ export const findListRoute = (router: ListsPluginRouter): void => { sortField, sortOrder, }); - const [validated, errors] = validate(exceptionList, findListResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + + return response.ok({ body: FindListsResponse.parse(exceptionList) }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts b/x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts index 6e9fdb29e55b86..80637788e00db6 100644 --- a/x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts @@ -5,12 +5,11 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_INDEX } from '@kbn/securitysolution-list-constants'; +import { GetListIndexResponse } from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { readListIndexResponse } from '../../../common/api'; import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; @@ -37,15 +36,12 @@ export const readListIndexRoute = (router: ListsPluginRouter): void => { const listItemDataStreamExists = await lists.getListItemDataStreamExists(); if (listDataStreamExists && listItemDataStreamExists) { - const [validated, errors] = validate( - { list_index: listDataStreamExists, list_item_index: listItemDataStreamExists }, - readListIndexResponse - ); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ + body: GetListIndexResponse.parse({ + list_index: listDataStreamExists, + list_item_index: listItemDataStreamExists, + }), + }); } else if (!listDataStreamExists && listItemDataStreamExists) { return siemResponse.error({ body: `data stream ${lists.getListName()} does not exist`, diff --git a/x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts index b3ab6f4e09eb76..2f8bd2738ae0f8 100644 --- a/x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts @@ -5,13 +5,16 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { + CreateListItemRequestBody, + CreateListItemResponse, +} from '@kbn/securitysolution-lists-common/api'; -import { createListItemRequest, createListItemResponse } from '../../../common/api'; import type { ListsPluginRouter } from '../../types'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const createListItemRoute = (router: ListsPluginRouter): void => { @@ -27,7 +30,7 @@ export const createListItemRoute = (router: ListsPluginRouter): void => { { validate: { request: { - body: buildRouteValidation(createListItemRequest), + body: buildRouteValidationWithZod(CreateListItemRequestBody), }, }, version: '2023-10-31', @@ -63,13 +66,9 @@ export const createListItemRoute = (router: ListsPluginRouter): void => { type: list.type, value, }); + if (createdListItem != null) { - const [validated, errors] = validate(createdListItem, createListItemResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: CreateListItemResponse.parse(createdListItem) }); } else { return siemResponse.error({ body: 'list item invalid', diff --git a/x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts index 644c8235bae06b..2cf30a61988b0c 100644 --- a/x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts @@ -5,17 +5,16 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { + DeleteListItemRequestQuery, + DeleteListItemResponse, +} from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { - deleteListItemArrayResponse, - deleteListItemRequestQuery, - deleteListItemResponse, -} from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const deleteListItemRoute = (router: ListsPluginRouter): void => { @@ -31,7 +30,7 @@ export const deleteListItemRoute = (router: ListsPluginRouter): void => { { validate: { request: { - query: buildRouteValidation(deleteListItemRequestQuery), + query: buildRouteValidationWithZod(DeleteListItemRequestQuery), }, }, version: '2023-10-31', @@ -50,12 +49,7 @@ export const deleteListItemRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(deleted, deleteListItemResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: DeleteListItemResponse.parse(deleted) }); } } else if (listId != null && value != null) { const list = await lists.getList({ id: listId }); @@ -77,12 +71,7 @@ export const deleteListItemRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(deleted, deleteListItemArrayResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: DeleteListItemResponse.parse(deleted) }); } } } else { diff --git a/x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts index 0fd4300ea51dc8..f65b678e362426 100644 --- a/x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts @@ -5,18 +5,17 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { + FindListItemsRequestQuery, + FindListItemsResponse, +} from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; import { decodeCursor } from '../../services/utils'; -import { - FindListItemRequestQueryDecoded, - findListItemRequestQuery, - findListItemResponse, -} from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse, getListClient } from '../utils'; +import { buildSiemResponse, getListClient } from '../utils'; export const findListItemRoute = (router: ListsPluginRouter): void => { router.versioned @@ -31,10 +30,7 @@ export const findListItemRoute = (router: ListsPluginRouter): void => { { validate: { request: { - query: buildRouteValidation< - typeof findListItemRequestQuery, - FindListItemRequestQueryDecoded - >(findListItemRequestQuery), + query: buildRouteValidationWithZod(FindListItemsRequestQuery), }, }, version: '2023-10-31', @@ -90,12 +86,7 @@ export const findListItemRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(exceptionList, findListItemResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: FindListItemsResponse.parse(exceptionList) }); } } } catch (err) { diff --git a/x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts index ff369aa9403e86..68c82e93fcc383 100644 --- a/x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts @@ -5,13 +5,16 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { + PatchListItemRequestBody, + PatchListItemResponse, +} from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { patchListItemRequest, patchListItemResponse } from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const patchListItemRoute = (router: ListsPluginRouter): void => { @@ -27,7 +30,7 @@ export const patchListItemRoute = (router: ListsPluginRouter): void => { { validate: { request: { - body: buildRouteValidation(patchListItemRequest), + body: buildRouteValidationWithZod(PatchListItemRequestBody), }, }, version: '2023-10-31', @@ -61,12 +64,7 @@ export const patchListItemRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(listItem, patchListItemResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: PatchListItemResponse.parse(listItem) }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts index 67c4793736483e..0e6a9dbe501552 100644 --- a/x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts @@ -5,17 +5,16 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { + GetListItemRequestQuery, + GetListItemResponse, +} from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { - readListItemArrayResponse, - readListItemRequestQuery, - readListItemResponse, -} from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const readListItemRoute = (router: ListsPluginRouter): void => { @@ -31,7 +30,7 @@ export const readListItemRoute = (router: ListsPluginRouter): void => { { validate: { request: { - query: buildRouteValidation(readListItemRequestQuery), + query: buildRouteValidationWithZod(GetListItemRequestQuery), }, }, version: '2023-10-31', @@ -49,12 +48,7 @@ export const readListItemRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(listItem, readListItemResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: GetListItemResponse.parse(listItem) }); } } else if (listId != null && value != null) { const list = await lists.getList({ id: listId }); @@ -75,12 +69,7 @@ export const readListItemRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(listItem, readListItemArrayResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: GetListItemResponse.parse(listItem) }); } } } else { diff --git a/x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts index c627f9e9e95ea2..8b2c4f65e54eb5 100644 --- a/x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts @@ -5,13 +5,16 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { + UpdateListItemRequestBody, + UpdateListItemResponse, +} from '@kbn/securitysolution-lists-common/api'; import type { ListsPluginRouter } from '../../types'; -import { updateListItemRequest, updateListItemResponse } from '../../../common/api'; -import { buildRouteValidation, buildSiemResponse } from '../utils'; +import { buildSiemResponse } from '../utils'; import { getListClient } from '..'; export const updateListItemRoute = (router: ListsPluginRouter): void => { @@ -27,7 +30,7 @@ export const updateListItemRoute = (router: ListsPluginRouter): void => { { validate: { request: { - body: buildRouteValidation(updateListItemRequest), + body: buildRouteValidationWithZod(UpdateListItemRequestBody), }, }, version: '2023-10-31', @@ -59,12 +62,7 @@ export const updateListItemRoute = (router: ListsPluginRouter): void => { statusCode: 404, }); } else { - const [validated, errors] = validate(listItem, updateListItemResponse); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ body: UpdateListItemResponse.parse(listItem) }); } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/lists/tsconfig.json b/x-pack/plugins/lists/tsconfig.json index b18887c2543361..47dc15c00ec8b8 100644 --- a/x-pack/plugins/lists/tsconfig.json +++ b/x-pack/plugins/lists/tsconfig.json @@ -1,15 +1,14 @@ - { "extends": "../../../tsconfig.base.json", "compilerOptions": { - "outDir": "target/types", + "outDir": "target/types" }, "include": [ "common/**/*", "public/**/*", "server/**/*", // have to declare *.json explicitly due to https://github.com/microsoft/TypeScript/issues/25636 - "server/**/*.json", + "server/**/*.json" ], "kbn_references": [ "@kbn/core", @@ -20,6 +19,7 @@ "@kbn/securitysolution-list-constants", "@kbn/securitysolution-list-hooks", "@kbn/securitysolution-list-api", + "@kbn/securitysolution-lists-common", "@kbn/kibana-react-plugin", "@kbn/i18n", "@kbn/data-plugin", @@ -39,8 +39,7 @@ "@kbn/utility-types", "@kbn/core-elasticsearch-client-server-mocks", "@kbn/core-saved-objects-server", + "@kbn/zod-helpers" ], - "exclude": [ - "target/**/*", - ] + "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts index 51e1843e9b8e8c..b6e7ae696b7556 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts @@ -6,11 +6,11 @@ */ import { transformError, BadRequestError, getIndexAliases } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { CreateAlertsMigrationRequestBody } from '../../../../../common/api/detection_engine/signals_migration'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import type { SetupPlugins } from '../../../../plugin'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_URL } from '../../../../../common/constants'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../utils'; import { getTemplateVersion } from '../index/check_template_version'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts index c2e364e58ca5be..f4452c73eaf78d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts @@ -6,11 +6,11 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { AlertsMigrationCleanupRequestBody } from '../../../../../common/api/detection_engine/signals_migration'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import type { SetupPlugins } from '../../../../plugin'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_URL } from '../../../../../common/constants'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../utils'; import { signalsMigrationService } from '../../migrations/migration_service'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts index bfec0f82867a6e..468baae7fdcad8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts @@ -7,11 +7,11 @@ import { transformError, BadRequestError } from '@kbn/securitysolution-es-utils'; import type { RuleDataPluginService } from '@kbn/rule-registry-plugin/server'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { FinalizeAlertsMigrationRequestBody } from '../../../../../common/api/detection_engine/signals_migration'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import type { SetupPlugins } from '../../../../plugin'; import { DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL } from '../../../../../common/constants'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { isMigrationFailed, isMigrationPending } from '../../migrations/helpers'; import { signalsMigrationService } from '../../migrations/migration_service'; import { buildSiemResponse } from '../utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/get_signals_migration_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/get_signals_migration_status_route.ts index 185e0c6ed61758..418db17b566c51 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/get_signals_migration_status_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/get_signals_migration_status_route.ts @@ -6,10 +6,10 @@ */ import { transformError, getIndexAliases } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { GetAlertsMigrationStatusRequestQuery } from '../../../../../common/api/detection_engine/signals_migration'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL } from '../../../../../common/constants'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { getIndexVersionsByIndex } from '../../migrations/get_index_versions_by_index'; import { getMigrationSavedObjectsByIndex } from '../../migrations/get_migration_saved_objects_by_index'; import { getSignalsIndicesInRange } from '../../migrations/get_signals_indices_in_range'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts index 3030e5fe799b6a..5db7cc16b05ec1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts @@ -14,7 +14,7 @@ import { } from '@kbn/rule-data-utils'; import type { ElasticsearchClient, Logger, StartServicesAccessor } from '@kbn/core/server'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { SetAlertsStatusRequestBody } from '../../../../../common/api/detection_engine/signals'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts index e868c2b9790182..60e0bde69c5902 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -9,8 +9,8 @@ import type { MappingRuntimeFields, Sort } from '@elastic/elasticsearch/lib/api/ import { transformError } from '@kbn/securitysolution-es-utils'; import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import type { AggregationsAggregationContainer } from '@elastic/elasticsearch/lib/api/types'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { SearchAlertsRequestBody } from '../../../../../common/api/detection_engine/signals'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts index f15342a36f46c8..1ce791143705b2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_assignees_route.ts @@ -7,6 +7,7 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { uniq } from 'lodash/fp'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { SetAlertAssigneesRequestBody } from '../../../../../common/api/detection_engine/alert_assignees'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { @@ -14,7 +15,6 @@ import { DETECTION_ENGINE_ALERT_ASSIGNEES_URL, } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { validateAlertAssigneesArrays } from './helpers'; export const setAlertAssigneesRoute = (router: SecuritySolutionPluginRouter) => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts index 95d722ac0a3811..c6997cc9a9bed8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/set_alert_tags_route.ts @@ -7,6 +7,7 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { uniq } from 'lodash/fp'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { ManageAlertTagsRequestBody } from '../../../../../common/api/detection_engine/alert_tags'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { @@ -14,7 +15,6 @@ import { DETECTION_ENGINE_ALERT_TAGS_URL, } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { validateAlertTagsArrays } from './helpers'; export const setAlertTagsRoute = (router: SecuritySolutionPluginRouter) => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts index 76787a82b7799f..1b1aeada056604 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/users/suggest_user_profiles_route.ts @@ -8,11 +8,11 @@ import type { IKibanaResponse, StartServicesAccessor } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_ALERT_SUGGEST_USERS_URL } from '../../../../../common/constants'; import { buildSiemResponse } from '../utils'; import type { StartPlugins } from '../../../../plugin'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { SuggestUserProfilesRequestQuery } from '../../../../../common/api/detection_engine/users'; export const suggestUserProfilesRoute = ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts index ff608a63440576..1177d4363fe292 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts @@ -8,6 +8,7 @@ import type { IKibanaResponse, Logger } from '@kbn/core/server'; import { AbortError } from '@kbn/kibana-utils-plugin/common'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { ConfigType } from '../../../../../../config'; import type { PerformBulkActionResponse } from '../../../../../../../common/api/detection_engine/rule_management'; import { @@ -22,7 +23,6 @@ import { } from '../../../../../../../common/constants'; import type { SetupPlugins } from '../../../../../../plugin'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { initPromisePool } from '../../../../../../utils/promise_pool'; import { routeLimitedConcurrencyTag } from '../../../../../../utils/route_limited_concurrency_tag'; import { buildMlAuthz } from '../../../../../machine_learning/authz'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts index ba6eebce2207c8..98910ea3376307 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts @@ -8,6 +8,7 @@ import type { IKibanaResponse, Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { DETECTION_ENGINE_RULES_BULK_CREATE } from '../../../../../../../common/constants'; import { BulkCreateRulesRequestBody, @@ -18,7 +19,6 @@ import { import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import { readRules } from '../../../logic/detection_rules_client/read_rules'; import { getDuplicates } from './get_duplicates'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { validateRuleDefaultExceptionList } from '../../../logic/exceptions/validate_rule_default_exception_list'; import { validateRulesWithDuplicatedDefaultExceptionsList } from '../../../logic/exceptions/validate_rules_with_duplicated_default_exceptions_list'; import { RULE_MANAGEMENT_BULK_ACTION_SOCKET_TIMEOUT_MS } from '../../timeouts'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts index 234439eb49052f..2f1ef59d0971bd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts @@ -8,6 +8,7 @@ import type { VersionedRouteConfig } from '@kbn/core-http-server'; import type { IKibanaResponse, Logger, RequestHandler } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { BulkCrudRulesResponse, BulkDeleteRulesRequestBody, @@ -18,7 +19,6 @@ import type { SecuritySolutionPluginRouter, SecuritySolutionRequestHandlerContext, } from '../../../../../../types'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse, createBulkErrorObject, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts index a3752d421380bb..aa06c04db06192 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts @@ -8,13 +8,12 @@ import type { IKibanaResponse, Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../../../common/constants'; import { BulkPatchRulesRequestBody, BulkCrudRulesResponse, } from '../../../../../../../common/api/detection_engine/rule_management'; - -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import { transformBulkError, buildSiemResponse } from '../../../../routes/utils'; import { getIdBulkError } from '../../../utils/utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts index e08d781cd74d8f..bae89a74ab0b1e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts @@ -6,15 +6,13 @@ */ import type { IKibanaResponse, Logger } from '@kbn/core/server'; - +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { transformError } from '@kbn/securitysolution-es-utils'; import { BulkUpdateRulesRequestBody, validateUpdateRuleProps, BulkCrudRulesResponse, } from '../../../../../../../common/api/detection_engine/rule_management'; - -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../../../common/constants'; import { getIdBulkError } from '../../../utils/utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts index 3819154c1b8a3c..aa6425b2e673ce 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts @@ -7,6 +7,7 @@ import type { IKibanaResponse } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { CreateRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management'; import { CreateRuleRequestBody, @@ -14,7 +15,6 @@ import { } from '../../../../../../../common/api/detection_engine/rule_management'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../routes/utils'; import { readRules } from '../../../logic/detection_rules_client/read_rules'; import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts index 3cf9aa6a2fb557..42a6a1c47544fe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts @@ -7,6 +7,7 @@ import type { IKibanaResponse } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { DeleteRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management'; import { DeleteRuleRequestQuery, @@ -14,7 +15,6 @@ import { } from '../../../../../../../common/api/detection_engine/rule_management'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../routes/utils'; import { readRules } from '../../../logic/detection_rules_client/read_rules'; import { getIdError, transform } from '../../../utils/utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts index 301bb62452f285..478a0ce02cc968 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts @@ -7,14 +7,12 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import type { Logger } from '@kbn/core/server'; - +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import { ExportRulesRequestBody, ExportRulesRequestQuery, } from '../../../../../../../common/api/detection_engine/rule_management'; - -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import type { ConfigType } from '../../../../../../config'; import { getNonPackagedRulesCount } from '../../../logic/search/get_existing_prepackaged_rules'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts index 3cbd164586a9df..02ff637ab6f109 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts @@ -7,7 +7,7 @@ import type { IKibanaResponse, Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; - +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { DETECTION_ENGINE_RULES_URL_FIND } from '../../../../../../../common/constants'; import type { FindRulesResponse } from '../../../../../../../common/api/detection_engine/rule_management'; import { @@ -18,7 +18,6 @@ import { import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import { findRules } from '../../../logic/search/find_rules'; import { buildSiemResponse } from '../../../../routes/utils'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { transformFindAlerts } from '../../../utils/utils'; export const findRulesRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts index 45379d3d175551..297a4cb587352b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/import_rules/route.ts @@ -11,6 +11,7 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { createPromiseFromStreams } from '@kbn/utils'; import { chunk } from 'lodash/fp'; import { extname } from 'path'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { ImportRulesRequestQuery, ImportRulesResponse, @@ -18,7 +19,6 @@ import { import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { ConfigType } from '../../../../../../config'; import type { HapiReadableStream, SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import type { BulkError, ImportRuleResponse } from '../../../../routes/utils'; import { buildSiemResponse, isBulkError, isImportRegular } from '../../../../routes/utils'; import { importRuleActionConnectors } from '../../../logic/import/action_connectors/import_rule_action_connectors'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts index 38b283b2c5fb67..506b36d4441dc6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts @@ -7,6 +7,7 @@ import type { IKibanaResponse } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { PatchRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management'; import { PatchRuleRequestBody, @@ -14,7 +15,6 @@ import { } from '../../../../../../../common/api/detection_engine/rule_management'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../routes/utils'; import { readRules } from '../../../logic/detection_rules_client/read_rules'; import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts index 95992618b06256..a119d1afae912b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts @@ -7,6 +7,7 @@ import type { IKibanaResponse, Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { ReadRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management'; import { ReadRuleRequestQuery, @@ -14,7 +15,6 @@ import { } from '../../../../../../../common/api/detection_engine/rule_management'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../routes/utils'; import { readRules } from '../../../logic/detection_rules_client/read_rules'; import { getIdError, transform } from '../../../utils/utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts index 5ac2df600908cf..5e77fa64e1fb96 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts @@ -7,6 +7,7 @@ import type { IKibanaResponse } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { UpdateRuleResponse } from '../../../../../../../common/api/detection_engine/rule_management'; import { UpdateRuleRequestBody, @@ -14,7 +15,6 @@ import { } from '../../../../../../../common/api/detection_engine/rule_management'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../routes/utils'; import { readRules } from '../../../logic/detection_rules_client/read_rules'; import { checkDefaultRuleExceptionListReferences } from '../../../logic/exceptions/check_for_default_rule_exception_list'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts index 4a01a6550cabcd..4e8001193b5c56 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.ts @@ -7,7 +7,7 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import type { IKibanaResponse } from '@kbn/core/server'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { buildSiemResponse } from '../../../../routes/utils'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.ts index 6c71652d27e343..bf3a9864260ac5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/api/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.ts @@ -7,8 +7,8 @@ import type { IKibanaResponse } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../routes/utils'; import type { GetRuleExecutionResultsResponse } from '../../../../../../../common/api/detection_engine/rule_monitoring'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts index 8c4137bf3d3866..c2faa464b75da5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts @@ -19,7 +19,7 @@ import type { import { parseDuration, DISABLE_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common'; import type { ExecutorType } from '@kbn/alerting-plugin/server/types'; import type { Alert } from '@kbn/alerting-plugin/server'; - +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { DEFAULT_PREVIEW_INDEX, DETECTION_ENGINE_RULES_PREVIEW, @@ -40,7 +40,6 @@ import { createPreviewRuleExecutionLogger } from './preview_rule_execution_logge import { parseInterval } from '../../../rule_types/utils/utils'; import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; -import { buildRouteValidationWithZod } from '../../../../../utils/build_validation/route_validation'; import { routeLimitedConcurrencyTag } from '../../../../../utils/route_limited_concurrency_tag'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts index e2737c6ebe0450..c7a0f07400cc85 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts @@ -7,6 +7,7 @@ import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionRequestHandlerContext } from '../../../../types'; import { ASSET_CRITICALITY_PUBLIC_URL, @@ -16,7 +17,6 @@ import { API_VERSIONS, } from '../../../../../common/constants'; import { DeleteAssetCriticalityRecord } from '../../../../../common/api/entity_analytics/asset_criticality'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setting_enabled'; import type { EntityAnalyticsRoutesDeps } from '../../types'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts index 57e52724b94cee..07d0cb3098dbc4 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts @@ -7,6 +7,7 @@ import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionRequestHandlerContext } from '../../../../types'; import { ASSET_CRITICALITY_INTERNAL_URL, @@ -16,7 +17,6 @@ import { API_VERSIONS, } from '../../../../../common/constants'; import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { AssetCriticalityRecordIdParts } from '../../../../../common/api/entity_analytics/asset_criticality'; import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setting_enabled'; import type { EntityAnalyticsRoutesDeps } from '../../types'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts index d367a1f8bd4d38..78fbe297862986 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts @@ -7,6 +7,7 @@ import type { IKibanaResponse, KibanaResponseFactory, Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { SecuritySolutionRequestHandlerContext } from '../../../../types'; import { ASSET_CRITICALITY_PUBLIC_URL, @@ -16,7 +17,6 @@ import { API_VERSIONS, } from '../../../../../common/constants'; import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { CreateAssetCriticalityRecord } from '../../../../../common/api/entity_analytics'; import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts index be4875d7dee04c..1602e724db2270 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/calculation.ts @@ -8,13 +8,13 @@ import type { Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { RiskScoresCalculationRequest } from '../../../../../common/api/entity_analytics/risk_engine/calculation_route.gen'; import { APP_ID, DEFAULT_RISK_SCORE_PAGE_SIZE, RISK_SCORE_CALCULATION_URL, } from '../../../../../common/constants'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { getRiskInputsIndex } from '../get_risk_inputs_index'; import type { EntityAnalyticsRoutesDeps } from '../../types'; import { RiskScoreAuditActions } from '../audit'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/entity_calculation.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/entity_calculation.ts index fe6e404e9e96db..eeb773b41a1808 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/entity_calculation.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/entity_calculation.ts @@ -5,16 +5,15 @@ * 2.0. */ +import { isEmpty } from 'lodash/fp'; import type { Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; - -import { isEmpty } from 'lodash/fp'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import type { RiskScoresCalculationResponse } from '../../../../../common/api/entity_analytics/risk_engine/calculation_route.gen'; import type { AfterKeys } from '../../../../../common/api/entity_analytics/common'; import { RiskScoresEntityCalculationRequest } from '../../../../../common/api/entity_analytics/risk_engine/entity_calculation_route.gen'; import { APP_ID, RISK_SCORE_ENTITY_CALCULATION_URL } from '../../../../../common/constants'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { getRiskInputsIndex } from '../get_risk_inputs_index'; import type { EntityAnalyticsRoutesDeps } from '../../types'; import { RiskScoreAuditActions } from '../audit'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts index 0979b5900737a1..d17dc8c99e19ea 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.ts @@ -8,14 +8,13 @@ import type { Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; - +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; import { RiskScoresPreviewRequest } from '../../../../../common/api/entity_analytics/risk_engine/preview_route.gen'; import { APP_ID, DEFAULT_RISK_SCORE_PAGE_SIZE, RISK_SCORE_PREVIEW_URL, } from '../../../../../common/constants'; -import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation'; import { getRiskInputsIndex } from '../get_risk_inputs_index'; import type { EntityAnalyticsRoutesDeps } from '../../types'; import { RiskScoreAuditActions } from '../audit'; diff --git a/x-pack/plugins/security_solution/server/utils/build_validation/route_validation.ts b/x-pack/plugins/security_solution/server/utils/build_validation/route_validation.ts index 7775186cde97f1..57692b515a2307 100644 --- a/x-pack/plugins/security_solution/server/utils/build_validation/route_validation.ts +++ b/x-pack/plugins/security_solution/server/utils/build_validation/route_validation.ts @@ -14,8 +14,6 @@ import type { RouteValidationResultFactory, RouteValidationError, } from '@kbn/core/server'; -import type { TypeOf, ZodType } from 'zod'; -import { stringifyZodError } from '@kbn/zod-helpers'; import type { GenericIntersectionC } from '../runtime_types'; import { excess } from '../runtime_types'; @@ -67,14 +65,3 @@ export const buildRouteValidationWithExcess = (validatedInput: A) => validationResult.ok(validatedInput) ) ); - -export const buildRouteValidationWithZod = - >(schema: T): RouteValidationFunction => - (inputValue: unknown, validationResult: RouteValidationResultFactory) => { - const decoded = schema.safeParse(inputValue); - if (decoded.success) { - return validationResult.ok(decoded.data); - } else { - return validationResult.badRequest(stringifyZodError(decoded.error)); - } - }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/lists_items/trial_license_complete_tier/items/find_list_items.ts b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/lists_items/trial_license_complete_tier/items/find_list_items.ts index 0c8aa8aa50fa8e..aed7d61acf7b23 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/lists_items/trial_license_complete_tier/items/find_list_items.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/lists_and_exception_lists/lists_items/trial_license_complete_tier/items/find_list_items.ts @@ -5,27 +5,20 @@ * 2.0. */ -import expect from '@kbn/expect'; +import expect from 'expect'; import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { LIST_ITEM_ID, LIST_ID } from '@kbn/lists-plugin/common/constants.mock'; -import { getListItemResponseMockWithoutAutoGeneratedValues } from '@kbn/lists-plugin/common/schemas/response/list_item_schema.mock'; import { getCreateMinimalListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_item_schema.mock'; import { getCreateMinimalListSchemaMock } from '@kbn/lists-plugin/common/schemas/request/create_list_schema.mock'; -import { - createListsIndex, - deleteListsIndex, - removeListItemServerGeneratedProperties, -} from '../../../utils'; +import { createListsIndex, deleteListsIndex } from '../../../utils'; import { FtrProviderContext } from '../../../../../ftr_provider_context'; export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); - const config = getService('config'); - const ELASTICSEARCH_USERNAME = config.get('servers.kibana.username'); describe('@ess @serverless find_list_items', () => { describe('find list items', () => { @@ -44,9 +37,9 @@ export default ({ getService }: FtrProviderContext): void => { .send() .expect(400); - expect(body).to.eql({ + expect(body).toEqual({ error: 'Bad Request', - message: '[request query]: Invalid value "undefined" supplied to "list_id"', + message: '[request query]: list_id: Required', statusCode: 400, }); }); @@ -58,8 +51,8 @@ export default ({ getService }: FtrProviderContext): void => { .send() .expect(404); - expect(body).to.eql({ - message: 'list id: "some-list-item-id" does not exist', + expect(body).toEqual({ + message: expect.any(String), status_code: 404, }); }); @@ -77,7 +70,7 @@ export default ({ getService }: FtrProviderContext): void => { .send() .expect(200); - expect(body).to.eql({ + expect(body).toEqual({ cursor: 'WzBd', data: [], page: 1, @@ -87,17 +80,12 @@ export default ({ getService }: FtrProviderContext): void => { }); it('should return a single list item when a single list item is loaded from a find with defaults added', async () => { - await supertest - .post(LIST_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListSchemaMock()) - .expect(200); + const listMock = getCreateMinimalListSchemaMock(); + const listItemMock = getCreateMinimalListItemSchemaMock(); - await supertest - .post(LIST_ITEM_URL) - .set('kbn-xsrf', 'true') - .send(getCreateMinimalListItemSchemaMock()) - .expect(200); + await supertest.post(LIST_URL).set('kbn-xsrf', 'true').send(listMock).expect(200); + + await supertest.post(LIST_ITEM_URL).set('kbn-xsrf', 'true').send(listItemMock).expect(200); const { body } = await supertest .get(`${LIST_ITEM_URL}/_find?list_id=${LIST_ID}`) @@ -105,11 +93,14 @@ export default ({ getService }: FtrProviderContext): void => { .send() .expect(200); - body.data = [removeListItemServerGeneratedProperties(body.data[0])]; - // cursor is a constant changing value so we have to delete it as well. - delete body.cursor; - expect(body).to.eql({ - data: [getListItemResponseMockWithoutAutoGeneratedValues(ELASTICSEARCH_USERNAME)], + expect(body).toMatchObject({ + data: [ + expect.objectContaining({ + list_id: listItemMock.list_id, + value: listItemMock.value, + type: listMock.type, + }), + ], page: 1, per_page: 20, total: 1, diff --git a/yarn.lock b/yarn.lock index a5738570ec3874..64ba753c576951 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5680,6 +5680,10 @@ version "0.0.0" uid "" +"@kbn/openapi-common@link:packages/kbn-openapi-common": + version "0.0.0" + uid "" + "@kbn/openapi-generator@link:packages/kbn-openapi-generator": version "0.0.0" uid "" @@ -6200,6 +6204,10 @@ version "0.0.0" uid "" +"@kbn/securitysolution-lists-common@link:packages/kbn-securitysolution-lists-common": + version "0.0.0" + uid "" + "@kbn/securitysolution-rules@link:packages/kbn-securitysolution-rules": version "0.0.0" uid "" From 858ef15c5a0dac61d0a4229a48ed8aad9a4a7f04 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Tue, 18 Jun 2024 22:29:29 +0200 Subject: [PATCH 060/123] [Security Solution] Auto-bundle Detections API OpenAPI specs (#186384) **Addresses:** https://github.com/elastic/kibana/issues/184428 ## Summary This PR adds scripts for automatic bundling Detections API OpenAPI spec as a part of PR pipeline. Corresponding resulting bundles are automatically committed to `x-pack/plugins/security_solution/docs/openapi/ess/` and `x-pack/plugins/security_solution/docs/openapi/serverless` folders. --- .../security_solution_openapi_bundling.sh | 10 + .../set_alert_assignees_route.schema.yaml | 3 +- ...les_and_timelines_status_route.schema.yaml | 3 +- ...uilt_rules_and_timelines_route.schema.yaml | 3 +- .../bulk_actions_route.schema.yaml | 3 +- .../bulk_create_rules_route.schema.yaml | 2 +- .../bulk_delete_rules_route.schema.yaml | 3 +- .../bulk_patch_rules_route.schema.yaml | 3 +- .../bulk_update_rules_route.schema.yaml | 3 +- .../create_rule/create_rule_route.schema.yaml | 2 +- .../delete_rule/delete_rule_route.schema.yaml | 3 +- .../patch_rule/patch_rule_route.schema.yaml | 3 +- .../read_rule/read_rule_route.schema.yaml | 3 +- .../update_rule/update_rule_route.schema.yaml | 3 +- .../export_rules_route.schema.yaml | 3 +- .../find_rules/find_rules_route.schema.yaml | 3 +- .../import_rules_route.schema.yaml | 3 +- .../read_tags/read_tags_route.schema.yaml | 3 +- ...et_rule_execution_events_route.schema.yaml | 4 +- ...t_rule_execution_results_route.schema.yaml | 4 +- .../suggest_user_profiles_route.schema.yaml | 4 +- ...ections_api_2023_10_31.bundled.schema.yaml | 5682 +++++++++++++++++ ...ections_api_2023_10_31.bundled.schema.yaml | 5485 ++++++++++++++++ .../scripts/openapi/bundle.js | 24 +- .../scripts/openapi/generate.js | 4 +- 25 files changed, 11237 insertions(+), 29 deletions(-) create mode 100644 .buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh create mode 100644 x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml create mode 100644 x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml diff --git a/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh new file mode 100644 index 00000000000000..be17669d980b60 --- /dev/null +++ b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/common/util.sh + +echo --- Security Solution OpenAPI Bundling + +(cd x-pack/plugins/security_solution && yarn openapi:bundle) +check_for_changed_files "yarn openapi:bundle" true diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml index 77fd51fe99494e..739386d637abd4 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml @@ -6,8 +6,9 @@ paths: /api/detection_engine/signals/assignees: summary: Assigns users to alerts post: - operationId: SetAlertAssignees + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: SetAlertAssignees description: Assigns users to alerts. requestBody: required: true diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml index 3a7a19611a1442..92b82e9d1e8496 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules/prepackaged/_status: get: - operationId: GetPrebuiltRulesAndTimelinesStatus + x-labels: [ess] x-codegen-enabled: true + operationId: GetPrebuiltRulesAndTimelinesStatus summary: Get the status of Elastic prebuilt rules tags: - Prebuilt Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml index 3aeb1b04317f9c..ab27c71c4ef331 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules/prepackaged: put: - operationId: InstallPrebuiltRulesAndTimelines + x-labels: [ess] x-codegen-enabled: true + operationId: InstallPrebuiltRulesAndTimelines summary: Installs all Elastic prebuilt rules and timelines tags: - Prebuilt Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml index 6b5a3aa1c69828..a2e75b8ae4fb69 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules/_bulk_action: post: - operationId: PerformBulkAction + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: PerformBulkAction summary: Applies a bulk action to multiple rules description: The bulk action is applied to all rules that match the filter or to the list of rules by their IDs. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml index 002fa5613eed93..127ad9784988db 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml @@ -6,8 +6,8 @@ paths: /api/detection_engine/rules/_bulk_create: post: x-labels: [ess] - operationId: BulkCreateRules x-codegen-enabled: true + operationId: BulkCreateRules deprecated: true description: Creates new detection rules in bulk. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml index 8438bb5b600520..02f78a65fee7cc 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules/_bulk_delete: delete: - operationId: BulkDeleteRules + x-labels: [ess] x-codegen-enabled: true + operationId: BulkDeleteRules deprecated: true description: Deletes multiple rules. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml index 7ba82e4ad36730..65bd0e1a4ac36d 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules/_bulk_update: patch: - operationId: BulkPatchRules + x-labels: [ess] x-codegen-enabled: true + operationId: BulkPatchRules deprecated: true description: Updates multiple rules using the `PATCH` method. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml index 6f85e51c6a01e6..37241035439d34 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules/_bulk_update: put: - operationId: BulkUpdateRules + x-labels: [ess] x-codegen-enabled: true + operationId: BulkUpdateRules deprecated: true description: Updates multiple rules using the `PUT` method. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml index 464a2df0641e37..a5071837af2cf5 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml @@ -6,8 +6,8 @@ paths: /api/detection_engine/rules: post: x-labels: [ess, serverless] - operationId: CreateRule x-codegen-enabled: true + operationId: CreateRule description: Create a single detection rule tags: - Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml index be55d0add83223..b6ef8a444eb559 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules: delete: - operationId: DeleteRule + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: DeleteRule description: Deletes a single rule using the `rule_id` or `id` field. tags: - Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml index df2bdb114c2e0a..aec02102bcca4e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules: patch: - operationId: PatchRule + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: PatchRule description: Patch a single rule tags: - Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml index bcb4cc83381dfc..817579eb8c27ea 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules: get: - operationId: ReadRule + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: ReadRule description: Read a single rule tags: - Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml index e32a3cd52e688f..de82265ca33793 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules: put: - operationId: UpdateRule + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: UpdateRule description: Update a single rule tags: - Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml index 73c60f76e19a86..0a88075abb1582 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml @@ -6,8 +6,9 @@ paths: /api/detection_engine/rules/_export: summary: Exports rules to an `.ndjson` file post: - operationId: ExportRules + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: ExportRules summary: Export rules description: Exports rules to an `.ndjson` file. The following configuration items are also included in the `.ndjson` file - Actions, Exception lists. Prebuilt rules cannot be exported. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml index 4a37d1f9f5bc91..4f27662e37bfd6 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml @@ -5,8 +5,9 @@ info: paths: /api/detection_engine/rules/_find: get: - operationId: FindRules + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: FindRules description: Finds rules that match the given query. tags: - Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml index ddc0f063747ec8..9056fcea04bcae 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml @@ -6,8 +6,9 @@ paths: /api/detection_engine/rules/_import: summary: Imports rules from an `.ndjson` file post: - operationId: ImportRules + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: ImportRules summary: Import rules description: Imports rules from an `.ndjson` file, including actions and exception lists. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml index ae4ef41a9ff32f..0a9d622dd2d4ab 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml @@ -6,8 +6,9 @@ paths: /api/detection_engine/tags: summary: Aggregates and returns rule tags get: - operationId: ReadTags + x-labels: [ess, serverless] x-codegen-enabled: true + operationId: ReadTags summary: Aggregates and returns all unique tags from all rules tags: - Tags API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.schema.yaml index 990ea4ef648765..c1f9a7cdd50967 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_events/get_rule_execution_events_route.schema.yaml @@ -5,8 +5,10 @@ info: paths: /internal/detection_engine/rules/{ruleId}/execution/events: put: - operationId: GetRuleExecutionEvents + x-labels: [ess, serverless] + x-internal: true x-codegen-enabled: true + operationId: GetRuleExecutionEvents summary: Returns execution events of a given rule (aggregated by execution UUID) from Event Log. tags: - Rule Execution Log API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.schema.yaml index 42f8d54a2e6166..a9a4eb2aca7e14 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.schema.yaml @@ -5,8 +5,10 @@ info: paths: /internal/detection_engine/rules/{ruleId}/execution/results: put: - operationId: GetRuleExecutionResults + x-labels: [ess, serverless] + x-internal: true x-codegen-enabled: true + operationId: GetRuleExecutionResults summary: Returns execution results of a given rule (aggregated by execution UUID) from Event Log. tags: - Rule Execution Log API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml index a4778969d03125..e4254bee52a373 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/users/suggest_user_profiles_route.schema.yaml @@ -6,8 +6,10 @@ paths: /internal/detection_engine/users/_find: summary: Suggests user profiles based on provided search term post: - operationId: SuggestUserProfiles + x-labels: [ess, serverless] + x-internal: true x-codegen-enabled: true + operationId: SuggestUserProfiles description: Suggests user profiles. parameters: - name: searchTerm diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml new file mode 100644 index 00000000000000..ca8bae8f42f0fd --- /dev/null +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -0,0 +1,5682 @@ +openapi: 3.0.3 +info: + description: >- + You can create rules that automatically turn events and external alerts sent + to Elastic Security into detection alerts. These alerts are displayed on the + Detections page. + title: Security Solution Detections API (Elastic Cloud and self-hosted) + version: '2023-10-31' +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + /api/detection_engine/rules: + delete: + description: Deletes a single rule using the `rule_id` or `id` field. + operationId: DeleteRule + parameters: + - description: The rule's `id` value. + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/RuleObjectId' + - description: The rule's `rule_id` value. + in: query + name: rule_id + required: false + schema: + $ref: '#/components/schemas/RuleSignatureId' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + get: + description: Read a single rule + operationId: ReadRule + parameters: + - description: The rule's `id` value. + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/RuleObjectId' + - description: The rule's `rule_id` value. + in: query + name: rule_id + required: false + schema: + $ref: '#/components/schemas/RuleSignatureId' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + patch: + description: Patch a single rule + operationId: PatchRule + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RulePatchProps' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + post: + description: Create a single detection rule + operationId: CreateRule + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RuleCreateProps' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + put: + description: Update a single rule + operationId: UpdateRule + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RuleUpdateProps' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + /api/detection_engine/rules/_bulk_action: + post: + description: >- + The bulk action is applied to all rules that match the filter or to the + list of rules by their IDs. + operationId: PerformBulkAction + parameters: + - description: Enables dry run mode for the request call. + in: query + name: dry_run + required: false + schema: + type: boolean + requestBody: + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/BulkDeleteRules' + - $ref: '#/components/schemas/BulkDisableRules' + - $ref: '#/components/schemas/BulkEnableRules' + - $ref: '#/components/schemas/BulkExportRules' + - $ref: '#/components/schemas/BulkDuplicateRules' + - $ref: '#/components/schemas/BulkEditRules' + responses: + '200': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/BulkEditActionResponse' + - $ref: '#/components/schemas/BulkExportActionResponse' + description: OK + summary: Applies a bulk action to multiple rules + tags: + - Bulk API + /api/detection_engine/rules/_bulk_create: + post: + deprecated: true + description: Creates new detection rules in bulk. + operationId: BulkCreateRules + requestBody: + content: + application/json: + schema: + items: + $ref: '#/components/schemas/RuleCreateProps' + type: array + description: 'A JSON array of rules, where each rule contains the required fields.' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BulkCrudRulesResponse' + description: Indicates a successful call. + tags: + - Bulk API + /api/detection_engine/rules/_bulk_delete: + delete: + deprecated: true + description: Deletes multiple rules. + operationId: BulkDeleteRules + requestBody: + content: + application/json: + schema: + items: + type: object + properties: + id: + $ref: '#/components/schemas/RuleObjectId' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + type: array + description: >- + A JSON array of `id` or `rule_id` fields of the rules you want to + delete. + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BulkCrudRulesResponse' + description: Indicates a successful call. + tags: + - Bulk API + /api/detection_engine/rules/_bulk_update: + patch: + deprecated: true + description: Updates multiple rules using the `PATCH` method. + operationId: BulkPatchRules + requestBody: + content: + application/json: + schema: + items: + $ref: '#/components/schemas/RulePatchProps' + type: array + description: 'A JSON array of rules, where each rule contains the required fields.' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BulkCrudRulesResponse' + description: Indicates a successful call. + tags: + - Bulk API + put: + deprecated: true + description: Updates multiple rules using the `PUT` method. + operationId: BulkUpdateRules + requestBody: + content: + application/json: + schema: + items: + $ref: '#/components/schemas/RuleUpdateProps' + type: array + description: >- + A JSON array where each element includes the `id` or `rule_id` field + of the rule you want to update and the fields you want to modify. + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BulkCrudRulesResponse' + description: Indicates a successful call. + tags: + - Bulk API + /api/detection_engine/rules/_export: + post: + description: >- + Exports rules to an `.ndjson` file. The following configuration items + are also included in the `.ndjson` file - Actions, Exception lists. + Prebuilt rules cannot be exported. + operationId: ExportRules + parameters: + - description: Determines whether a summary of the exported rules is returned. + in: query + name: exclude_export_details + required: false + schema: + default: false + type: boolean + - description: File name for saving the exported rules. + in: query + name: file_name + required: false + schema: + default: export.ndjson + type: string + requestBody: + content: + application/json: + schema: + nullable: true + type: object + properties: + objects: + description: >- + Array of `rule_id` fields. Exports all rules when + unspecified. + items: + type: object + properties: + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + required: + - rule_id + type: array + required: + - objects + required: false + responses: + '200': + content: + application/ndjson: + schema: + description: An `.ndjson` file containing the returned rules. + format: binary + type: string + description: Indicates a successful call. + summary: Export rules + tags: + - Import/Export API + summary: Exports rules to an `.ndjson` file + /api/detection_engine/rules/_find: + get: + description: Finds rules that match the given query. + operationId: FindRules + parameters: + - in: query + name: fields + required: false + schema: + items: + type: string + type: array + - description: Search query + in: query + name: filter + required: false + schema: + type: string + - description: Field to sort by + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/FindRulesSortField' + - description: Sort order + in: query + name: sort_order + required: false + schema: + $ref: '#/components/schemas/SortOrder' + - description: Page number + in: query + name: page + required: false + schema: + default: 1 + minimum: 1 + type: integer + - description: Rules per page + in: query + name: per_page + required: false + schema: + default: 20 + minimum: 0 + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + items: + $ref: '#/components/schemas/RuleResponse' + type: array + page: + type: integer + perPage: + type: integer + total: + type: integer + required: + - page + - perPage + - total + - data + description: Successful response + tags: + - Rules API + /api/detection_engine/rules/_import: + post: + description: >- + Imports rules from an `.ndjson` file, including actions and exception + lists. + operationId: ImportRules + parameters: + - description: >- + Determines whether existing rules with the same `rule_id` are + overwritten. + in: query + name: overwrite + required: false + schema: + default: false + type: boolean + - description: >- + Determines whether existing exception lists with the same `list_id` + are overwritten. + in: query + name: overwrite_exceptions + required: false + schema: + default: false + type: boolean + - description: >- + Determines whether existing actions with the same + `kibana.alert.rule.actions.id` are overwritten. + in: query + name: overwrite_action_connectors + required: false + schema: + default: false + type: boolean + - description: Generates a new list ID for each imported exception list. + in: query + name: as_new_list + required: false + schema: + default: false + type: boolean + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + description: The `.ndjson` file containing the rules. + format: binary + type: string + required: true + responses: + '200': + content: + application/json: + schema: + additionalProperties: false + type: object + properties: + action_connectors_errors: + items: + $ref: '#/components/schemas/ErrorSchema' + type: array + action_connectors_success: + type: boolean + action_connectors_success_count: + minimum: 0 + type: integer + action_connectors_warnings: + items: + $ref: '#/components/schemas/WarningSchema' + type: array + errors: + items: + $ref: '#/components/schemas/ErrorSchema' + type: array + exceptions_errors: + items: + $ref: '#/components/schemas/ErrorSchema' + type: array + exceptions_success: + type: boolean + exceptions_success_count: + minimum: 0 + type: integer + rules_count: + minimum: 0 + type: integer + success: + type: boolean + success_count: + minimum: 0 + type: integer + required: + - exceptions_success + - exceptions_success_count + - exceptions_errors + - rules_count + - success + - success_count + - errors + - action_connectors_errors + - action_connectors_warnings + - action_connectors_success + - action_connectors_success_count + description: Indicates a successful call. + summary: Import rules + tags: + - Import/Export API + summary: Imports rules from an `.ndjson` file + /api/detection_engine/rules/prepackaged: + put: + operationId: InstallPrebuiltRulesAndTimelines + responses: + '200': + content: + application/json: + schema: + additionalProperties: false + type: object + properties: + rules_installed: + description: The number of rules installed + minimum: 0 + type: integer + rules_updated: + description: The number of rules updated + minimum: 0 + type: integer + timelines_installed: + description: The number of timelines installed + minimum: 0 + type: integer + timelines_updated: + description: The number of timelines updated + minimum: 0 + type: integer + required: + - rules_installed + - rules_updated + - timelines_installed + - timelines_updated + description: Indicates a successful call + summary: Installs all Elastic prebuilt rules and timelines + tags: + - Prebuilt Rules API + /api/detection_engine/rules/prepackaged/_status: + get: + operationId: GetPrebuiltRulesAndTimelinesStatus + responses: + '200': + content: + application/json: + schema: + additionalProperties: false + type: object + properties: + rules_custom_installed: + description: The total number of custom rules + minimum: 0 + type: integer + rules_installed: + description: The total number of installed prebuilt rules + minimum: 0 + type: integer + rules_not_installed: + description: >- + The total number of available prebuilt rules that are not + installed + minimum: 0 + type: integer + rules_not_updated: + description: The total number of outdated prebuilt rules + minimum: 0 + type: integer + timelines_installed: + description: The total number of installed prebuilt timelines + minimum: 0 + type: integer + timelines_not_installed: + description: >- + The total number of available prebuilt timelines that are + not installed + minimum: 0 + type: integer + timelines_not_updated: + description: The total number of outdated prebuilt timelines + minimum: 0 + type: integer + required: + - rules_custom_installed + - rules_installed + - rules_not_installed + - rules_not_updated + - timelines_installed + - timelines_not_installed + - timelines_not_updated + description: Indicates a successful call + summary: Get the status of Elastic prebuilt rules + tags: + - Prebuilt Rules API + /api/detection_engine/signals/assignees: + post: + description: Assigns users to alerts. + operationId: SetAlertAssignees + requestBody: + content: + application/json: + schema: + type: object + properties: + assignees: + $ref: '#/components/schemas/AlertAssignees' + description: Details about the assignees to assign and unassign. + ids: + $ref: '#/components/schemas/AlertIds' + description: List of alerts ids to assign and unassign passed assignees. + required: + - assignees + - ids + required: true + responses: + '200': + description: Indicates a successful call. + '400': + description: Invalid request. + summary: Assigns users to alerts + /api/detection_engine/tags: + get: + operationId: ReadTags + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleTagArray' + description: Indicates a successful call + summary: Aggregates and returns all unique tags from all rules + tags: + - Tags API + summary: Aggregates and returns rule tags +components: + schemas: + AlertAssignees: + type: object + properties: + add: + description: A list of users ids to assign. + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + remove: + description: A list of users ids to unassign. + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + required: + - add + - remove + AlertIds: + description: A list of alerts ids. + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + AlertsIndex: + deprecated: true + description: (deprecated) Has no effect. + type: string + AlertsIndexNamespace: + description: Has no effect. + type: string + AlertSuppression: + type: object + properties: + duration: + $ref: '#/components/schemas/AlertSuppressionDuration' + group_by: + $ref: '#/components/schemas/AlertSuppressionGroupBy' + missing_fields_strategy: + $ref: '#/components/schemas/AlertSuppressionMissingFieldsStrategy' + required: + - group_by + AlertSuppressionDuration: + type: object + properties: + unit: + enum: + - s + - m + - h + type: string + value: + minimum: 1 + type: integer + required: + - value + - unit + AlertSuppressionGroupBy: + items: + type: string + maxItems: 3 + minItems: 1 + type: array + AlertSuppressionMissingFieldsStrategy: + description: >- + Describes how alerts will be generated for documents with missing + suppress by fields: + + doNotSuppress - per each document a separate alert will be created + + suppress - only alert will be created per suppress by bucket + enum: + - doNotSuppress + - suppress + type: string + AnomalyThreshold: + description: Anomaly threshold + minimum: 0 + type: integer + BuildingBlockType: + description: >- + Determines if the rule acts as a building block. By default, + building-block alerts are not displayed in the UI. These rules are used + as a foundation for other rules that do generate alerts. Its value must + be default. + type: string + BulkActionEditPayload: + anyOf: + - $ref: '#/components/schemas/BulkActionEditPayloadTags' + - $ref: '#/components/schemas/BulkActionEditPayloadIndexPatterns' + - $ref: '#/components/schemas/BulkActionEditPayloadInvestigationFields' + - $ref: '#/components/schemas/BulkActionEditPayloadTimeline' + - $ref: '#/components/schemas/BulkActionEditPayloadRuleActions' + - $ref: '#/components/schemas/BulkActionEditPayloadSchedule' + BulkActionEditPayloadIndexPatterns: + type: object + properties: + overwrite_data_views: + type: boolean + type: + enum: + - add_index_patterns + - delete_index_patterns + - set_index_patterns + type: string + value: + $ref: '#/components/schemas/IndexPatternArray' + required: + - type + - value + BulkActionEditPayloadInvestigationFields: + type: object + properties: + type: + enum: + - add_investigation_fields + - delete_investigation_fields + - set_investigation_fields + type: string + value: + $ref: '#/components/schemas/InvestigationFields' + required: + - type + - value + BulkActionEditPayloadRuleActions: + type: object + properties: + type: + enum: + - add_rule_actions + - set_rule_actions + type: string + value: + type: object + properties: + actions: + items: + $ref: '#/components/schemas/NormalizedRuleAction' + type: array + throttle: + $ref: '#/components/schemas/ThrottleForBulkActions' + required: + - actions + required: + - type + - value + BulkActionEditPayloadSchedule: + type: object + properties: + type: + enum: + - set_schedule + type: string + value: + type: object + properties: + interval: + description: Interval in which the rule is executed + example: 1h + pattern: '^[1-9]\d*[smh]$' + type: string + lookback: + description: Lookback time for the rule + example: 1h + pattern: '^[1-9]\d*[smh]$' + type: string + required: + - interval + - lookback + required: + - type + - value + BulkActionEditPayloadTags: + type: object + properties: + type: + enum: + - add_tags + - delete_tags + - set_tags + type: string + value: + $ref: '#/components/schemas/RuleTagArray' + required: + - type + - value + BulkActionEditPayloadTimeline: + type: object + properties: + type: + enum: + - set_timeline + type: string + value: + type: object + properties: + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + required: + - timeline_id + - timeline_title + required: + - type + - value + BulkActionsDryRunErrCode: + enum: + - IMMUTABLE + - MACHINE_LEARNING_AUTH + - MACHINE_LEARNING_INDEX_PATTERN + - ESQL_INDEX_PATTERN + - INVESTIGATION_FIELDS_FEATURE + type: string + BulkActionSkipResult: + type: object + properties: + id: + type: string + name: + type: string + skip_reason: + $ref: '#/components/schemas/BulkEditSkipReason' + required: + - id + - skip_reason + BulkCrudRulesResponse: + items: + oneOf: + - $ref: '#/components/schemas/RuleResponse' + - $ref: '#/components/schemas/ErrorSchema' + type: array + BulkDeleteRules: + type: object + properties: + action: + enum: + - delete + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + BulkDisableRules: + type: object + properties: + action: + enum: + - disable + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + BulkDuplicateRules: + type: object + properties: + action: + enum: + - duplicate + type: string + duplicate: + type: object + properties: + include_exceptions: + description: Whether to copy exceptions from the original rule + type: boolean + include_expired_exceptions: + description: Whether to copy expired exceptions from the original rule + type: boolean + required: + - include_exceptions + - include_expired_exceptions + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + BulkEditActionResponse: + type: object + properties: + attributes: + type: object + properties: + errors: + items: + $ref: '#/components/schemas/NormalizedRuleError' + type: array + results: + $ref: '#/components/schemas/BulkEditActionResults' + summary: + $ref: '#/components/schemas/BulkEditActionSummary' + required: + - results + - summary + message: + type: string + rules_count: + type: integer + status_code: + type: integer + success: + type: boolean + required: + - attributes + BulkEditActionResults: + type: object + properties: + created: + items: + $ref: '#/components/schemas/RuleResponse' + type: array + deleted: + items: + $ref: '#/components/schemas/RuleResponse' + type: array + skipped: + items: + $ref: '#/components/schemas/BulkActionSkipResult' + type: array + updated: + items: + $ref: '#/components/schemas/RuleResponse' + type: array + required: + - updated + - created + - deleted + - skipped + BulkEditActionSummary: + type: object + properties: + failed: + type: integer + skipped: + type: integer + succeeded: + type: integer + total: + type: integer + required: + - failed + - skipped + - succeeded + - total + BulkEditRules: + type: object + properties: + action: + enum: + - edit + type: string + edit: + description: Array of objects containing the edit operations + items: + $ref: '#/components/schemas/BulkActionEditPayload' + minItems: 1 + type: array + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + - edit + BulkEditSkipReason: + enum: + - RULE_NOT_MODIFIED + type: string + BulkEnableRules: + type: object + properties: + action: + enum: + - enable + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + BulkExportActionResponse: + type: string + BulkExportRules: + type: object + properties: + action: + enum: + - export + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + ConcurrentSearches: + minimum: 1 + type: integer + DataViewId: + type: string + DefaultParams: + type: object + properties: + command: + enum: + - isolate + type: string + comment: + type: string + required: + - command + EcsMapping: + additionalProperties: + type: object + properties: + field: + type: string + value: + oneOf: + - type: string + - items: + type: string + type: array + type: object + EndpointResponseAction: + type: object + properties: + action_type_id: + enum: + - .endpoint + type: string + params: + oneOf: + - $ref: '#/components/schemas/DefaultParams' + - $ref: '#/components/schemas/ProcessesParams' + required: + - action_type_id + - params + EqlOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + event_category_override: + $ref: '#/components/schemas/EventCategoryOverride' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + tiebreaker_field: + $ref: '#/components/schemas/TiebreakerField' + timestamp_field: + $ref: '#/components/schemas/TimestampField' + EqlQueryLanguage: + enum: + - eql + type: string + EqlRequiredFields: + type: object + properties: + language: + $ref: '#/components/schemas/EqlQueryLanguage' + description: Query language to use + query: + $ref: '#/components/schemas/RuleQuery' + description: EQL query to execute + type: + description: Rule type + enum: + - eql + type: string + required: + - type + - query + - language + EqlRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/EqlRuleResponseFields' + EqlRuleCreateFields: + allOf: + - $ref: '#/components/schemas/EqlRequiredFields' + - $ref: '#/components/schemas/EqlOptionalFields' + EqlRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/EqlRuleCreateFields' + EqlRulePatchFields: + allOf: + - type: object + properties: + language: + $ref: '#/components/schemas/EqlQueryLanguage' + description: Query language to use + query: + $ref: '#/components/schemas/RuleQuery' + description: EQL query to execute + type: + description: Rule type + enum: + - eql + type: string + - $ref: '#/components/schemas/EqlOptionalFields' + EqlRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/EqlRulePatchFields' + EqlRuleResponseFields: + allOf: + - $ref: '#/components/schemas/EqlRequiredFields' + - $ref: '#/components/schemas/EqlOptionalFields' + EqlRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/EqlRuleCreateFields' + ErrorSchema: + additionalProperties: false + type: object + properties: + error: + type: object + properties: + message: + type: string + status_code: + minimum: 400 + type: integer + required: + - status_code + - message + id: + type: string + item_id: + minLength: 1 + type: string + list_id: + minLength: 1 + type: string + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + required: + - error + EsqlQueryLanguage: + enum: + - esql + type: string + EsqlRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/EsqlRuleResponseFields' + EsqlRuleCreateFields: + allOf: + - $ref: '#/components/schemas/EsqlRuleOptionalFields' + - $ref: '#/components/schemas/EsqlRuleRequiredFields' + EsqlRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/EsqlRuleCreateFields' + EsqlRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + EsqlRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + language: + $ref: '#/components/schemas/EsqlQueryLanguage' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + query: + $ref: '#/components/schemas/RuleQuery' + description: ESQL query to execute + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + type: + description: Rule type + enum: + - esql + type: string + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/EsqlRuleOptionalFields' + EsqlRuleRequiredFields: + type: object + properties: + language: + $ref: '#/components/schemas/EsqlQueryLanguage' + query: + $ref: '#/components/schemas/RuleQuery' + description: ESQL query to execute + type: + description: Rule type + enum: + - esql + type: string + required: + - type + - language + - query + EsqlRuleResponseFields: + allOf: + - $ref: '#/components/schemas/EsqlRuleOptionalFields' + - $ref: '#/components/schemas/EsqlRuleRequiredFields' + EsqlRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/EsqlRuleCreateFields' + EventCategoryOverride: + type: string + ExceptionListType: + description: The exception type + enum: + - detection + - rule_default + - endpoint + - endpoint_trusted_apps + - endpoint_events + - endpoint_host_isolation_exceptions + - endpoint_blocklists + type: string + ExternalRuleSource: + description: >- + Type of rule source for externally sourced rules, i.e. rules that have + an external source, such as the Elastic Prebuilt rules repo. + type: object + properties: + is_customized: + $ref: '#/components/schemas/IsExternalRuleCustomized' + type: + enum: + - external + type: string + required: + - type + - is_customized + FindRulesSortField: + enum: + - created_at + - createdAt + - enabled + - execution_summary.last_execution.date + - execution_summary.last_execution.metrics.execution_gap_duration_s + - execution_summary.last_execution.metrics.total_indexing_duration_ms + - execution_summary.last_execution.metrics.total_search_duration_ms + - execution_summary.last_execution.status + - name + - risk_score + - riskScore + - severity + - updated_at + - updatedAt + type: string + HistoryWindowStart: + $ref: '#/components/schemas/NonEmptyString' + IndexPatternArray: + items: + type: string + type: array + InternalRuleSource: + description: >- + Type of rule source for internally sourced rules, i.e. created within + the Kibana apps. + type: object + properties: + type: + enum: + - internal + type: string + required: + - type + InvestigationFields: + type: object + properties: + field_names: + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + required: + - field_names + InvestigationGuide: + description: Notes to help investigate alerts produced by the rule. + type: string + IsExternalRuleCustomized: + description: >- + Determines whether an external/prebuilt rule has been customized by the + user (i.e. any of its fields have been modified and diverged from the + base value). + type: boolean + IsRuleEnabled: + description: Determines whether the rule is enabled. + type: boolean + IsRuleImmutable: + deprecated: true + description: >- + This field determines whether the rule is a prebuilt Elastic rule. It + will be replaced with the `rule_source` field. + type: boolean + ItemsPerSearch: + minimum: 1 + type: integer + KqlQueryLanguage: + enum: + - kuery + - lucene + type: string + MachineLearningJobId: + description: Machine learning job ID + oneOf: + - type: string + - items: + type: string + minItems: 1 + type: array + MachineLearningRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/MachineLearningRuleResponseFields' + MachineLearningRuleCreateFields: + $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + MachineLearningRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/MachineLearningRuleCreateFields' + MachineLearningRulePatchFields: + type: object + properties: + anomaly_threshold: + $ref: '#/components/schemas/AnomalyThreshold' + machine_learning_job_id: + $ref: '#/components/schemas/MachineLearningJobId' + type: + description: Rule type + enum: + - machine_learning + type: string + MachineLearningRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/MachineLearningRulePatchFields' + MachineLearningRuleRequiredFields: + type: object + properties: + anomaly_threshold: + $ref: '#/components/schemas/AnomalyThreshold' + machine_learning_job_id: + $ref: '#/components/schemas/MachineLearningJobId' + type: + description: Rule type + enum: + - machine_learning + type: string + required: + - type + - machine_learning_job_id + - anomaly_threshold + MachineLearningRuleResponseFields: + $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + MachineLearningRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/MachineLearningRuleCreateFields' + MaxSignals: + minimum: 1 + type: integer + NewTermsFields: + items: + type: string + maxItems: 3 + minItems: 1 + type: array + NewTermsRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/NewTermsRuleResponseFields' + NewTermsRuleCreateFields: + allOf: + - $ref: '#/components/schemas/NewTermsRuleRequiredFields' + - $ref: '#/components/schemas/NewTermsRuleOptionalFields' + - $ref: '#/components/schemas/NewTermsRuleDefaultableFields' + NewTermsRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/NewTermsRuleCreateFields' + NewTermsRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + NewTermsRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + NewTermsRulePatchFields: + allOf: + - type: object + properties: + history_window_start: + $ref: '#/components/schemas/HistoryWindowStart' + new_terms_fields: + $ref: '#/components/schemas/NewTermsFields' + query: + $ref: '#/components/schemas/RuleQuery' + type: + description: Rule type + enum: + - new_terms + type: string + - $ref: '#/components/schemas/NewTermsRuleOptionalFields' + - $ref: '#/components/schemas/NewTermsRuleDefaultableFields' + NewTermsRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/NewTermsRulePatchFields' + NewTermsRuleRequiredFields: + type: object + properties: + history_window_start: + $ref: '#/components/schemas/HistoryWindowStart' + new_terms_fields: + $ref: '#/components/schemas/NewTermsFields' + query: + $ref: '#/components/schemas/RuleQuery' + type: + description: Rule type + enum: + - new_terms + type: string + required: + - type + - query + - new_terms_fields + - history_window_start + NewTermsRuleResponseFields: + allOf: + - $ref: '#/components/schemas/NewTermsRuleRequiredFields' + - $ref: '#/components/schemas/NewTermsRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + required: + - language + NewTermsRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/NewTermsRuleCreateFields' + NonEmptyString: + description: A string that is not empty and does not contain only whitespace + minLength: 1 + pattern: ^(?! *$).+$ + type: string + NormalizedRuleAction: + additionalProperties: false + type: object + properties: + alerts_filter: + $ref: '#/components/schemas/RuleActionAlertsFilter' + frequency: + $ref: '#/components/schemas/RuleActionFrequency' + group: + $ref: '#/components/schemas/RuleActionGroup' + id: + $ref: '#/components/schemas/RuleActionId' + params: + $ref: '#/components/schemas/RuleActionParams' + required: + - group + - id + - params + NormalizedRuleError: + type: object + properties: + err_code: + $ref: '#/components/schemas/BulkActionsDryRunErrCode' + message: + type: string + rules: + items: + $ref: '#/components/schemas/RuleDetailsInError' + type: array + status_code: + type: integer + required: + - message + - status_code + - rules + OsqueryParams: + type: object + properties: + ecs_mapping: + $ref: '#/components/schemas/EcsMapping' + pack_id: + type: string + queries: + items: + $ref: '#/components/schemas/OsqueryQuery' + type: array + query: + type: string + saved_query_id: + type: string + timeout: + type: number + OsqueryQuery: + type: object + properties: + ecs_mapping: + $ref: '#/components/schemas/EcsMapping' + id: + description: Query ID + type: string + platform: + type: string + query: + description: Query to execute + type: string + removed: + type: boolean + snapshot: + type: boolean + version: + description: Query version + type: string + required: + - id + - query + OsqueryResponseAction: + type: object + properties: + action_type_id: + enum: + - .osquery + type: string + params: + $ref: '#/components/schemas/OsqueryParams' + required: + - action_type_id + - params + ProcessesParams: + type: object + properties: + command: + enum: + - kill-process + - suspend-process + type: string + comment: + type: string + config: + type: object + properties: + field: + description: Field to use instead of process.pid + type: string + overwrite: + default: true + description: Whether to overwrite field with process.pid + type: boolean + required: + - field + required: + - command + - config + QueryRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/QueryRuleResponseFields' + QueryRuleCreateFields: + allOf: + - $ref: '#/components/schemas/QueryRuleRequiredFields' + - $ref: '#/components/schemas/QueryRuleOptionalFields' + - $ref: '#/components/schemas/QueryRuleDefaultableFields' + QueryRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/QueryRuleCreateFields' + QueryRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + query: + $ref: '#/components/schemas/RuleQuery' + QueryRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array + saved_id: + $ref: '#/components/schemas/SavedQueryId' + QueryRulePatchFields: + allOf: + - type: object + properties: + type: + description: Rule type + enum: + - query + type: string + - $ref: '#/components/schemas/QueryRuleOptionalFields' + - $ref: '#/components/schemas/QueryRuleDefaultableFields' + QueryRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/QueryRulePatchFields' + QueryRuleRequiredFields: + type: object + properties: + type: + description: Rule type + enum: + - query + type: string + required: + - type + QueryRuleResponseFields: + allOf: + - $ref: '#/components/schemas/QueryRuleRequiredFields' + - $ref: '#/components/schemas/QueryRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + query: + $ref: '#/components/schemas/RuleQuery' + required: + - query + - language + QueryRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/QueryRuleCreateFields' + RelatedIntegration: + type: object + properties: + integration: + $ref: '#/components/schemas/NonEmptyString' + package: + $ref: '#/components/schemas/NonEmptyString' + version: + $ref: '#/components/schemas/NonEmptyString' + required: + - package + - version + RelatedIntegrationArray: + items: + $ref: '#/components/schemas/RelatedIntegration' + type: array + RequiredField: + description: Describes an Elasticsearch field that is needed for the rule to function + type: object + properties: + ecs: + description: Whether the field is an ECS field + type: boolean + name: + $ref: '#/components/schemas/NonEmptyString' + description: Name of an Elasticsearch field + type: + $ref: '#/components/schemas/NonEmptyString' + description: Type of the Elasticsearch field + required: + - name + - type + - ecs + RequiredFieldArray: + items: + $ref: '#/components/schemas/RequiredField' + type: array + RequiredFieldInput: + description: >- + Input parameters to create a RequiredField. Does not include the `ecs` + field, because `ecs` is calculated on the backend based on the field + name and type. + type: object + properties: + name: + $ref: '#/components/schemas/NonEmptyString' + description: Name of an Elasticsearch field + type: + $ref: '#/components/schemas/NonEmptyString' + description: Type of an Elasticsearch field + required: + - name + - type + ResponseAction: + oneOf: + - $ref: '#/components/schemas/OsqueryResponseAction' + - $ref: '#/components/schemas/EndpointResponseAction' + ResponseFields: + type: object + properties: + created_at: + format: date-time + type: string + created_by: + type: string + execution_summary: + $ref: '#/components/schemas/RuleExecutionSummary' + id: + $ref: '#/components/schemas/RuleObjectId' + immutable: + $ref: '#/components/schemas/IsRuleImmutable' + required_fields: + $ref: '#/components/schemas/RequiredFieldArray' + revision: + minimum: 0 + type: integer + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_source: + $ref: '#/components/schemas/RuleSource' + updated_at: + format: date-time + type: string + updated_by: + type: string + required: + - id + - rule_id + - immutable + - updated_at + - updated_by + - created_at + - created_by + - revision + - related_integrations + - required_fields + RiskScore: + description: Risk score (0 to 100) + maximum: 100 + minimum: 0 + type: integer + RiskScoreMapping: + description: >- + Overrides generated alerts' risk_score with a value from the source + event + items: + type: object + properties: + field: + type: string + operator: + enum: + - equals + type: string + risk_score: + $ref: '#/components/schemas/RiskScore' + value: + type: string + required: + - field + - operator + - value + type: array + RuleAction: + type: object + properties: + action_type_id: + description: The action type used for sending notifications. + type: string + alerts_filter: + $ref: '#/components/schemas/RuleActionAlertsFilter' + frequency: + $ref: '#/components/schemas/RuleActionFrequency' + group: + $ref: '#/components/schemas/RuleActionGroup' + id: + $ref: '#/components/schemas/RuleActionId' + params: + $ref: '#/components/schemas/RuleActionParams' + uuid: + $ref: '#/components/schemas/NonEmptyString' + required: + - action_type_id + - group + - id + - params + RuleActionAlertsFilter: + additionalProperties: true + type: object + RuleActionFrequency: + description: >- + The action frequency defines when the action runs (for example, only on + rule execution or at specific time intervals). + type: object + properties: + notifyWhen: + $ref: '#/components/schemas/RuleActionNotifyWhen' + summary: + description: >- + Action summary indicates whether we will send a summary notification + about all the generate alerts or notification per individual alert + type: boolean + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + nullable: true + required: + - summary + - notifyWhen + - throttle + RuleActionGroup: + description: >- + Optionally groups actions by use cases. Use `default` for alert + notifications. + type: string + RuleActionId: + description: The connector ID. + type: string + RuleActionNotifyWhen: + description: >- + The condition for throttling the notification: `onActionGroupChange`, + `onActiveAlert`, or `onThrottleInterval` + enum: + - onActiveAlert + - onThrottleInterval + - onActionGroupChange + type: string + RuleActionParams: + additionalProperties: true + description: >- + Object containing the allowed connector fields, which varies according + to the connector type. + type: object + RuleActionThrottle: + description: Defines the interval on which a rule's actions are executed. + oneOf: + - enum: + - no_actions + - rule + type: string + - description: 'Time interval in seconds, minutes, hours, or days.' + example: 1h + pattern: '^[1-9]\d*[smhd]$' + type: string + RuleAuthorArray: + items: + type: string + type: array + RuleCreateProps: + anyOf: + - $ref: '#/components/schemas/EqlRuleCreateProps' + - $ref: '#/components/schemas/QueryRuleCreateProps' + - $ref: '#/components/schemas/SavedQueryRuleCreateProps' + - $ref: '#/components/schemas/ThresholdRuleCreateProps' + - $ref: '#/components/schemas/ThreatMatchRuleCreateProps' + - $ref: '#/components/schemas/MachineLearningRuleCreateProps' + - $ref: '#/components/schemas/NewTermsRuleCreateProps' + - $ref: '#/components/schemas/EsqlRuleCreateProps' + discriminator: + propertyName: type + RuleDescription: + minLength: 1 + type: string + RuleDetailsInError: + type: object + properties: + id: + type: string + name: + type: string + required: + - id + RuleExceptionList: + type: object + properties: + id: + $ref: '#/components/schemas/NonEmptyString' + description: ID of the exception container + list_id: + $ref: '#/components/schemas/NonEmptyString' + description: List ID of the exception container + namespace_type: + description: Determines the exceptions validity in rule's Kibana space + enum: + - agnostic + - single + type: string + type: + $ref: '#/components/schemas/ExceptionListType' + required: + - id + - list_id + - type + - namespace_type + RuleExecutionMetrics: + type: object + properties: + execution_gap_duration_s: + description: Duration in seconds of execution gap + minimum: 0 + type: integer + total_enrichment_duration_ms: + description: >- + Total time spent enriching documents during current rule execution + cycle + minimum: 0 + type: integer + total_indexing_duration_ms: + description: >- + Total time spent indexing documents during current rule execution + cycle + minimum: 0 + type: integer + total_search_duration_ms: + description: >- + Total time spent performing ES searches as measured by Kibana; + includes network latency and time spent serializing/deserializing + request/response + minimum: 0 + type: integer + RuleExecutionStatus: + description: >- + Custom execution status of Security rules that is different from the + status used in the Alerting Framework. We merge our custom status with + the Framework's status to determine the resulting status of a rule. + + - going to run - @deprecated Replaced by the 'running' status but left + for backwards compatibility with rule execution events already written + to Event Log in the prior versions of Kibana. Don't use when writing + rule status changes. + + - running - Rule execution started but not reached any intermediate or + final status. + + - partial failure - Rule can partially fail for various reasons either + in the middle of an execution (in this case we update its status right + away) or in the end of it. So currently this status can be both + intermediate and final at the same time. A typical reason for a partial + failure: not all the indices that the rule searches over actually exist. + + - failed - Rule failed to execute due to unhandled exception or a reason + defined in the business logic of its executor function. + + - succeeded - Rule executed successfully without any issues. Note: this + status is just an indication of a rule's "health". The rule might or + might not generate any alerts despite of it. + enum: + - going to run + - running + - partial failure + - failed + - succeeded + type: string + RuleExecutionStatusOrder: + type: integer + RuleExecutionSummary: + type: object + properties: + last_execution: + type: object + properties: + date: + description: Date of the last execution + format: date-time + type: string + message: + type: string + metrics: + $ref: '#/components/schemas/RuleExecutionMetrics' + status: + $ref: '#/components/schemas/RuleExecutionStatus' + description: Status of the last execution + status_order: + $ref: '#/components/schemas/RuleExecutionStatusOrder' + required: + - date + - status + - status_order + - message + - metrics + required: + - last_execution + RuleFalsePositiveArray: + items: + type: string + type: array + RuleFilterArray: + items: {} + type: array + RuleInterval: + description: >- + Frequency of rule execution, using a date math range. For example, "1h" + means the rule runs every hour. Defaults to 5m (5 minutes). + type: string + RuleIntervalFrom: + description: >- + Time from which data is analyzed each time the rule executes, using a + date math range. For example, now-4200s means the rule analyzes data + from 70 minutes before its start time. Defaults to now-6m (analyzes data + from 6 minutes before the start time). + format: date-math + type: string + RuleIntervalTo: + type: string + RuleLicense: + description: The rule's license. + type: string + RuleMetadata: + additionalProperties: true + type: object + RuleName: + minLength: 1 + type: string + RuleNameOverride: + description: Sets the source field for the alert's signal.rule.name value + type: string + RuleObjectId: + $ref: '#/components/schemas/UUID' + RulePatchProps: + anyOf: + - $ref: '#/components/schemas/EqlRulePatchProps' + - $ref: '#/components/schemas/QueryRulePatchProps' + - $ref: '#/components/schemas/SavedQueryRulePatchProps' + - $ref: '#/components/schemas/ThresholdRulePatchProps' + - $ref: '#/components/schemas/ThreatMatchRulePatchProps' + - $ref: '#/components/schemas/MachineLearningRulePatchProps' + - $ref: '#/components/schemas/NewTermsRulePatchProps' + - $ref: '#/components/schemas/EsqlRulePatchProps' + RuleQuery: + type: string + RuleReferenceArray: + items: + type: string + type: array + RuleResponse: + anyOf: + - $ref: '#/components/schemas/EqlRule' + - $ref: '#/components/schemas/QueryRule' + - $ref: '#/components/schemas/SavedQueryRule' + - $ref: '#/components/schemas/ThresholdRule' + - $ref: '#/components/schemas/ThreatMatchRule' + - $ref: '#/components/schemas/MachineLearningRule' + - $ref: '#/components/schemas/NewTermsRule' + - $ref: '#/components/schemas/EsqlRule' + discriminator: + propertyName: type + RuleSignatureId: + description: 'Could be any string, not necessarily a UUID' + type: string + RuleSource: + description: >- + Discriminated union that determines whether the rule is internally + sourced (created within the Kibana app) or has an external source, such + as the Elastic Prebuilt rules repo. + discriminator: + propertyName: type + oneOf: + - $ref: '#/components/schemas/ExternalRuleSource' + - $ref: '#/components/schemas/InternalRuleSource' + RuleTagArray: + description: >- + String array containing words and phrases to help categorize, filter, + and search rules. Defaults to an empty array. + items: + type: string + type: array + RuleUpdateProps: + anyOf: + - $ref: '#/components/schemas/EqlRuleUpdateProps' + - $ref: '#/components/schemas/QueryRuleUpdateProps' + - $ref: '#/components/schemas/SavedQueryRuleUpdateProps' + - $ref: '#/components/schemas/ThresholdRuleUpdateProps' + - $ref: '#/components/schemas/ThreatMatchRuleUpdateProps' + - $ref: '#/components/schemas/MachineLearningRuleUpdateProps' + - $ref: '#/components/schemas/NewTermsRuleUpdateProps' + - $ref: '#/components/schemas/EsqlRuleUpdateProps' + discriminator: + propertyName: type + RuleVersion: + description: The rule's version number. + minimum: 1 + type: integer + SavedObjectResolveAliasPurpose: + enum: + - savedObjectConversion + - savedObjectImport + type: string + SavedObjectResolveAliasTargetId: + type: string + SavedObjectResolveOutcome: + enum: + - exactMatch + - aliasMatch + - conflict + type: string + SavedQueryId: + type: string + SavedQueryRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/SavedQueryRuleResponseFields' + SavedQueryRuleCreateFields: + allOf: + - $ref: '#/components/schemas/SavedQueryRuleRequiredFields' + - $ref: '#/components/schemas/SavedQueryRuleOptionalFields' + - $ref: '#/components/schemas/SavedQueryRuleDefaultableFields' + SavedQueryRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/SavedQueryRuleCreateFields' + SavedQueryRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + SavedQueryRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + query: + $ref: '#/components/schemas/RuleQuery' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array + SavedQueryRulePatchFields: + allOf: + - type: object + properties: + saved_id: + $ref: '#/components/schemas/SavedQueryId' + type: + description: Rule type + enum: + - saved_query + type: string + - $ref: '#/components/schemas/SavedQueryRuleOptionalFields' + - $ref: '#/components/schemas/SavedQueryRuleDefaultableFields' + SavedQueryRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/SavedQueryRulePatchFields' + SavedQueryRuleRequiredFields: + type: object + properties: + saved_id: + $ref: '#/components/schemas/SavedQueryId' + type: + description: Rule type + enum: + - saved_query + type: string + required: + - type + - saved_id + SavedQueryRuleResponseFields: + allOf: + - $ref: '#/components/schemas/SavedQueryRuleRequiredFields' + - $ref: '#/components/schemas/SavedQueryRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + required: + - language + SavedQueryRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/SavedQueryRuleCreateFields' + SetupGuide: + type: string + Severity: + description: Severity of the rule + enum: + - low + - medium + - high + - critical + type: string + SeverityMapping: + description: Overrides generated alerts' severity with values from the source event + items: + type: object + properties: + field: + type: string + operator: + enum: + - equals + type: string + severity: + $ref: '#/components/schemas/Severity' + value: + type: string + required: + - field + - operator + - severity + - value + type: array + SortOrder: + enum: + - asc + - desc + type: string + Threat: + type: object + properties: + framework: + description: Relevant attack framework + type: string + tactic: + $ref: '#/components/schemas/ThreatTactic' + technique: + description: Array containing information on the attack techniques (optional) + items: + $ref: '#/components/schemas/ThreatTechnique' + type: array + required: + - framework + - tactic + ThreatArray: + items: + $ref: '#/components/schemas/Threat' + type: array + ThreatFilters: + items: + description: >- + Query and filter context array used to filter documents from the + Elasticsearch index containing the threat values + type: array + ThreatIndex: + items: + type: string + type: array + ThreatIndicatorPath: + description: >- + Defines the path to the threat indicator in the indicator documents + (optional) + type: string + ThreatMapping: + items: + type: object + properties: + entries: + items: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + type: + enum: + - mapping + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - field + - type + - value + type: array + required: + - entries + minItems: 1 + type: array + ThreatMatchRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/ThreatMatchRuleResponseFields' + ThreatMatchRuleCreateFields: + allOf: + - $ref: '#/components/schemas/ThreatMatchRuleRequiredFields' + - $ref: '#/components/schemas/ThreatMatchRuleOptionalFields' + - $ref: '#/components/schemas/ThreatMatchRuleDefaultableFields' + ThreatMatchRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/ThreatMatchRuleCreateFields' + ThreatMatchRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + ThreatMatchRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + concurrent_searches: + $ref: '#/components/schemas/ConcurrentSearches' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + items_per_search: + $ref: '#/components/schemas/ItemsPerSearch' + saved_id: + $ref: '#/components/schemas/SavedQueryId' + threat_filters: + $ref: '#/components/schemas/ThreatFilters' + threat_indicator_path: + $ref: '#/components/schemas/ThreatIndicatorPath' + threat_language: + $ref: '#/components/schemas/KqlQueryLanguage' + ThreatMatchRulePatchFields: + allOf: + - type: object + properties: + query: + $ref: '#/components/schemas/RuleQuery' + threat_index: + $ref: '#/components/schemas/ThreatIndex' + threat_mapping: + $ref: '#/components/schemas/ThreatMapping' + threat_query: + $ref: '#/components/schemas/ThreatQuery' + type: + description: Rule type + enum: + - threat_match + type: string + - $ref: '#/components/schemas/ThreatMatchRuleOptionalFields' + - $ref: '#/components/schemas/ThreatMatchRuleDefaultableFields' + ThreatMatchRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/ThreatMatchRulePatchFields' + ThreatMatchRuleRequiredFields: + type: object + properties: + query: + $ref: '#/components/schemas/RuleQuery' + threat_index: + $ref: '#/components/schemas/ThreatIndex' + threat_mapping: + $ref: '#/components/schemas/ThreatMapping' + threat_query: + $ref: '#/components/schemas/ThreatQuery' + type: + description: Rule type + enum: + - threat_match + type: string + required: + - type + - query + - threat_query + - threat_mapping + - threat_index + ThreatMatchRuleResponseFields: + allOf: + - $ref: '#/components/schemas/ThreatMatchRuleRequiredFields' + - $ref: '#/components/schemas/ThreatMatchRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + required: + - language + ThreatMatchRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/ThreatMatchRuleCreateFields' + ThreatQuery: + description: Query to execute + type: string + ThreatSubtechnique: + type: object + properties: + id: + description: Subtechnique ID + type: string + name: + description: Subtechnique name + type: string + reference: + description: Subtechnique reference + type: string + required: + - id + - name + - reference + ThreatTactic: + type: object + properties: + id: + description: Tactic ID + type: string + name: + description: Tactic name + type: string + reference: + description: Tactic reference + type: string + required: + - id + - name + - reference + ThreatTechnique: + type: object + properties: + id: + description: Technique ID + type: string + name: + description: Technique name + type: string + reference: + description: Technique reference + type: string + subtechnique: + description: Array containing more specific information on the attack technique + items: + $ref: '#/components/schemas/ThreatSubtechnique' + type: array + required: + - id + - name + - reference + Threshold: + type: object + properties: + cardinality: + $ref: '#/components/schemas/ThresholdCardinality' + field: + $ref: '#/components/schemas/ThresholdField' + value: + $ref: '#/components/schemas/ThresholdValue' + required: + - field + - value + ThresholdAlertSuppression: + type: object + properties: + duration: + $ref: '#/components/schemas/AlertSuppressionDuration' + required: + - duration + ThresholdCardinality: + items: + type: object + properties: + field: + type: string + value: + minimum: 0 + type: integer + required: + - field + - value + type: array + ThresholdField: + description: Field to aggregate on + oneOf: + - type: string + - items: + type: string + type: array + ThresholdRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/ThresholdRuleResponseFields' + ThresholdRuleCreateFields: + allOf: + - $ref: '#/components/schemas/ThresholdRuleRequiredFields' + - $ref: '#/components/schemas/ThresholdRuleOptionalFields' + - $ref: '#/components/schemas/ThresholdRuleDefaultableFields' + ThresholdRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/ThresholdRuleCreateFields' + ThresholdRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + ThresholdRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/ThresholdAlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + saved_id: + $ref: '#/components/schemas/SavedQueryId' + ThresholdRulePatchFields: + allOf: + - type: object + properties: + query: + $ref: '#/components/schemas/RuleQuery' + threshold: + $ref: '#/components/schemas/Threshold' + type: + description: Rule type + enum: + - threshold + type: string + - $ref: '#/components/schemas/ThresholdRuleOptionalFields' + - $ref: '#/components/schemas/ThresholdRuleDefaultableFields' + ThresholdRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/ThresholdRulePatchFields' + ThresholdRuleRequiredFields: + type: object + properties: + query: + $ref: '#/components/schemas/RuleQuery' + threshold: + $ref: '#/components/schemas/Threshold' + type: + description: Rule type + enum: + - threshold + type: string + required: + - type + - query + - threshold + ThresholdRuleResponseFields: + allOf: + - $ref: '#/components/schemas/ThresholdRuleRequiredFields' + - $ref: '#/components/schemas/ThresholdRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + required: + - language + ThresholdRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/ThresholdRuleCreateFields' + ThresholdValue: + description: Threshold value + minimum: 1 + type: integer + ThrottleForBulkActions: + description: >- + The condition for throttling the notification: 'rule', 'no_actions', or + time duration + enum: + - rule + - 1h + - 1d + - 7d + type: string + TiebreakerField: + description: Sets a secondary field for sorting events + type: string + TimelineTemplateId: + description: Timeline template ID + type: string + TimelineTemplateTitle: + description: Timeline template title + type: string + TimestampField: + description: Contains the event timestamp used for sorting a sequence of events + type: string + TimestampOverride: + description: Sets the time field used to query indices + type: string + TimestampOverrideFallbackDisabled: + description: Disables the fallback to the event's @timestamp field + type: boolean + UUID: + description: A universally unique identifier + format: uuid + type: string + WarningSchema: + type: object + properties: + actionPath: + type: string + buttonLabel: + type: string + message: + type: string + type: + type: string + required: + - type + - message + - actionPath + securitySchemes: + BasicAuth: + scheme: basic + type: http +security: + - BasicAuth: [] diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml new file mode 100644 index 00000000000000..94682a8e1b8f97 --- /dev/null +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -0,0 +1,5485 @@ +openapi: 3.0.3 +info: + description: >- + You can create rules that automatically turn events and external alerts sent + to Elastic Security into detection alerts. These alerts are displayed on the + Detections page. + title: Security Solution Detections API (Elastic Cloud Serverless) + version: '2023-10-31' +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + /api/detection_engine/rules: + delete: + description: Deletes a single rule using the `rule_id` or `id` field. + operationId: DeleteRule + parameters: + - description: The rule's `id` value. + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/RuleObjectId' + - description: The rule's `rule_id` value. + in: query + name: rule_id + required: false + schema: + $ref: '#/components/schemas/RuleSignatureId' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + get: + description: Read a single rule + operationId: ReadRule + parameters: + - description: The rule's `id` value. + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/RuleObjectId' + - description: The rule's `rule_id` value. + in: query + name: rule_id + required: false + schema: + $ref: '#/components/schemas/RuleSignatureId' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + patch: + description: Patch a single rule + operationId: PatchRule + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RulePatchProps' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + post: + description: Create a single detection rule + operationId: CreateRule + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RuleCreateProps' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + put: + description: Update a single rule + operationId: UpdateRule + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RuleUpdateProps' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleResponse' + description: Indicates a successful call. + tags: + - Rules API + /api/detection_engine/rules/_bulk_action: + post: + description: >- + The bulk action is applied to all rules that match the filter or to the + list of rules by their IDs. + operationId: PerformBulkAction + parameters: + - description: Enables dry run mode for the request call. + in: query + name: dry_run + required: false + schema: + type: boolean + requestBody: + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/BulkDeleteRules' + - $ref: '#/components/schemas/BulkDisableRules' + - $ref: '#/components/schemas/BulkEnableRules' + - $ref: '#/components/schemas/BulkExportRules' + - $ref: '#/components/schemas/BulkDuplicateRules' + - $ref: '#/components/schemas/BulkEditRules' + responses: + '200': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/BulkEditActionResponse' + - $ref: '#/components/schemas/BulkExportActionResponse' + description: OK + summary: Applies a bulk action to multiple rules + tags: + - Bulk API + /api/detection_engine/rules/_export: + post: + description: >- + Exports rules to an `.ndjson` file. The following configuration items + are also included in the `.ndjson` file - Actions, Exception lists. + Prebuilt rules cannot be exported. + operationId: ExportRules + parameters: + - description: Determines whether a summary of the exported rules is returned. + in: query + name: exclude_export_details + required: false + schema: + default: false + type: boolean + - description: File name for saving the exported rules. + in: query + name: file_name + required: false + schema: + default: export.ndjson + type: string + requestBody: + content: + application/json: + schema: + nullable: true + type: object + properties: + objects: + description: >- + Array of `rule_id` fields. Exports all rules when + unspecified. + items: + type: object + properties: + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + required: + - rule_id + type: array + required: + - objects + required: false + responses: + '200': + content: + application/ndjson: + schema: + description: An `.ndjson` file containing the returned rules. + format: binary + type: string + description: Indicates a successful call. + summary: Export rules + tags: + - Import/Export API + summary: Exports rules to an `.ndjson` file + /api/detection_engine/rules/_find: + get: + description: Finds rules that match the given query. + operationId: FindRules + parameters: + - in: query + name: fields + required: false + schema: + items: + type: string + type: array + - description: Search query + in: query + name: filter + required: false + schema: + type: string + - description: Field to sort by + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/FindRulesSortField' + - description: Sort order + in: query + name: sort_order + required: false + schema: + $ref: '#/components/schemas/SortOrder' + - description: Page number + in: query + name: page + required: false + schema: + default: 1 + minimum: 1 + type: integer + - description: Rules per page + in: query + name: per_page + required: false + schema: + default: 20 + minimum: 0 + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + items: + $ref: '#/components/schemas/RuleResponse' + type: array + page: + type: integer + perPage: + type: integer + total: + type: integer + required: + - page + - perPage + - total + - data + description: Successful response + tags: + - Rules API + /api/detection_engine/rules/_import: + post: + description: >- + Imports rules from an `.ndjson` file, including actions and exception + lists. + operationId: ImportRules + parameters: + - description: >- + Determines whether existing rules with the same `rule_id` are + overwritten. + in: query + name: overwrite + required: false + schema: + default: false + type: boolean + - description: >- + Determines whether existing exception lists with the same `list_id` + are overwritten. + in: query + name: overwrite_exceptions + required: false + schema: + default: false + type: boolean + - description: >- + Determines whether existing actions with the same + `kibana.alert.rule.actions.id` are overwritten. + in: query + name: overwrite_action_connectors + required: false + schema: + default: false + type: boolean + - description: Generates a new list ID for each imported exception list. + in: query + name: as_new_list + required: false + schema: + default: false + type: boolean + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + description: The `.ndjson` file containing the rules. + format: binary + type: string + required: true + responses: + '200': + content: + application/json: + schema: + additionalProperties: false + type: object + properties: + action_connectors_errors: + items: + $ref: '#/components/schemas/ErrorSchema' + type: array + action_connectors_success: + type: boolean + action_connectors_success_count: + minimum: 0 + type: integer + action_connectors_warnings: + items: + $ref: '#/components/schemas/WarningSchema' + type: array + errors: + items: + $ref: '#/components/schemas/ErrorSchema' + type: array + exceptions_errors: + items: + $ref: '#/components/schemas/ErrorSchema' + type: array + exceptions_success: + type: boolean + exceptions_success_count: + minimum: 0 + type: integer + rules_count: + minimum: 0 + type: integer + success: + type: boolean + success_count: + minimum: 0 + type: integer + required: + - exceptions_success + - exceptions_success_count + - exceptions_errors + - rules_count + - success + - success_count + - errors + - action_connectors_errors + - action_connectors_warnings + - action_connectors_success + - action_connectors_success_count + description: Indicates a successful call. + summary: Import rules + tags: + - Import/Export API + summary: Imports rules from an `.ndjson` file + /api/detection_engine/signals/assignees: + post: + description: Assigns users to alerts. + operationId: SetAlertAssignees + requestBody: + content: + application/json: + schema: + type: object + properties: + assignees: + $ref: '#/components/schemas/AlertAssignees' + description: Details about the assignees to assign and unassign. + ids: + $ref: '#/components/schemas/AlertIds' + description: List of alerts ids to assign and unassign passed assignees. + required: + - assignees + - ids + required: true + responses: + '200': + description: Indicates a successful call. + '400': + description: Invalid request. + summary: Assigns users to alerts + /api/detection_engine/tags: + get: + operationId: ReadTags + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RuleTagArray' + description: Indicates a successful call + summary: Aggregates and returns all unique tags from all rules + tags: + - Tags API + summary: Aggregates and returns rule tags +components: + schemas: + AlertAssignees: + type: object + properties: + add: + description: A list of users ids to assign. + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + remove: + description: A list of users ids to unassign. + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + required: + - add + - remove + AlertIds: + description: A list of alerts ids. + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + AlertsIndex: + deprecated: true + description: (deprecated) Has no effect. + type: string + AlertsIndexNamespace: + description: Has no effect. + type: string + AlertSuppression: + type: object + properties: + duration: + $ref: '#/components/schemas/AlertSuppressionDuration' + group_by: + $ref: '#/components/schemas/AlertSuppressionGroupBy' + missing_fields_strategy: + $ref: '#/components/schemas/AlertSuppressionMissingFieldsStrategy' + required: + - group_by + AlertSuppressionDuration: + type: object + properties: + unit: + enum: + - s + - m + - h + type: string + value: + minimum: 1 + type: integer + required: + - value + - unit + AlertSuppressionGroupBy: + items: + type: string + maxItems: 3 + minItems: 1 + type: array + AlertSuppressionMissingFieldsStrategy: + description: >- + Describes how alerts will be generated for documents with missing + suppress by fields: + + doNotSuppress - per each document a separate alert will be created + + suppress - only alert will be created per suppress by bucket + enum: + - doNotSuppress + - suppress + type: string + AnomalyThreshold: + description: Anomaly threshold + minimum: 0 + type: integer + BuildingBlockType: + description: >- + Determines if the rule acts as a building block. By default, + building-block alerts are not displayed in the UI. These rules are used + as a foundation for other rules that do generate alerts. Its value must + be default. + type: string + BulkActionEditPayload: + anyOf: + - $ref: '#/components/schemas/BulkActionEditPayloadTags' + - $ref: '#/components/schemas/BulkActionEditPayloadIndexPatterns' + - $ref: '#/components/schemas/BulkActionEditPayloadInvestigationFields' + - $ref: '#/components/schemas/BulkActionEditPayloadTimeline' + - $ref: '#/components/schemas/BulkActionEditPayloadRuleActions' + - $ref: '#/components/schemas/BulkActionEditPayloadSchedule' + BulkActionEditPayloadIndexPatterns: + type: object + properties: + overwrite_data_views: + type: boolean + type: + enum: + - add_index_patterns + - delete_index_patterns + - set_index_patterns + type: string + value: + $ref: '#/components/schemas/IndexPatternArray' + required: + - type + - value + BulkActionEditPayloadInvestigationFields: + type: object + properties: + type: + enum: + - add_investigation_fields + - delete_investigation_fields + - set_investigation_fields + type: string + value: + $ref: '#/components/schemas/InvestigationFields' + required: + - type + - value + BulkActionEditPayloadRuleActions: + type: object + properties: + type: + enum: + - add_rule_actions + - set_rule_actions + type: string + value: + type: object + properties: + actions: + items: + $ref: '#/components/schemas/NormalizedRuleAction' + type: array + throttle: + $ref: '#/components/schemas/ThrottleForBulkActions' + required: + - actions + required: + - type + - value + BulkActionEditPayloadSchedule: + type: object + properties: + type: + enum: + - set_schedule + type: string + value: + type: object + properties: + interval: + description: Interval in which the rule is executed + example: 1h + pattern: '^[1-9]\d*[smh]$' + type: string + lookback: + description: Lookback time for the rule + example: 1h + pattern: '^[1-9]\d*[smh]$' + type: string + required: + - interval + - lookback + required: + - type + - value + BulkActionEditPayloadTags: + type: object + properties: + type: + enum: + - add_tags + - delete_tags + - set_tags + type: string + value: + $ref: '#/components/schemas/RuleTagArray' + required: + - type + - value + BulkActionEditPayloadTimeline: + type: object + properties: + type: + enum: + - set_timeline + type: string + value: + type: object + properties: + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + required: + - timeline_id + - timeline_title + required: + - type + - value + BulkActionsDryRunErrCode: + enum: + - IMMUTABLE + - MACHINE_LEARNING_AUTH + - MACHINE_LEARNING_INDEX_PATTERN + - ESQL_INDEX_PATTERN + - INVESTIGATION_FIELDS_FEATURE + type: string + BulkActionSkipResult: + type: object + properties: + id: + type: string + name: + type: string + skip_reason: + $ref: '#/components/schemas/BulkEditSkipReason' + required: + - id + - skip_reason + BulkDeleteRules: + type: object + properties: + action: + enum: + - delete + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + BulkDisableRules: + type: object + properties: + action: + enum: + - disable + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + BulkDuplicateRules: + type: object + properties: + action: + enum: + - duplicate + type: string + duplicate: + type: object + properties: + include_exceptions: + description: Whether to copy exceptions from the original rule + type: boolean + include_expired_exceptions: + description: Whether to copy expired exceptions from the original rule + type: boolean + required: + - include_exceptions + - include_expired_exceptions + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + BulkEditActionResponse: + type: object + properties: + attributes: + type: object + properties: + errors: + items: + $ref: '#/components/schemas/NormalizedRuleError' + type: array + results: + $ref: '#/components/schemas/BulkEditActionResults' + summary: + $ref: '#/components/schemas/BulkEditActionSummary' + required: + - results + - summary + message: + type: string + rules_count: + type: integer + status_code: + type: integer + success: + type: boolean + required: + - attributes + BulkEditActionResults: + type: object + properties: + created: + items: + $ref: '#/components/schemas/RuleResponse' + type: array + deleted: + items: + $ref: '#/components/schemas/RuleResponse' + type: array + skipped: + items: + $ref: '#/components/schemas/BulkActionSkipResult' + type: array + updated: + items: + $ref: '#/components/schemas/RuleResponse' + type: array + required: + - updated + - created + - deleted + - skipped + BulkEditActionSummary: + type: object + properties: + failed: + type: integer + skipped: + type: integer + succeeded: + type: integer + total: + type: integer + required: + - failed + - skipped + - succeeded + - total + BulkEditRules: + type: object + properties: + action: + enum: + - edit + type: string + edit: + description: Array of objects containing the edit operations + items: + $ref: '#/components/schemas/BulkActionEditPayload' + minItems: 1 + type: array + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + - edit + BulkEditSkipReason: + enum: + - RULE_NOT_MODIFIED + type: string + BulkEnableRules: + type: object + properties: + action: + enum: + - enable + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + BulkExportActionResponse: + type: string + BulkExportRules: + type: object + properties: + action: + enum: + - export + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + required: + - action + ConcurrentSearches: + minimum: 1 + type: integer + DataViewId: + type: string + DefaultParams: + type: object + properties: + command: + enum: + - isolate + type: string + comment: + type: string + required: + - command + EcsMapping: + additionalProperties: + type: object + properties: + field: + type: string + value: + oneOf: + - type: string + - items: + type: string + type: array + type: object + EndpointResponseAction: + type: object + properties: + action_type_id: + enum: + - .endpoint + type: string + params: + oneOf: + - $ref: '#/components/schemas/DefaultParams' + - $ref: '#/components/schemas/ProcessesParams' + required: + - action_type_id + - params + EqlOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + event_category_override: + $ref: '#/components/schemas/EventCategoryOverride' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + tiebreaker_field: + $ref: '#/components/schemas/TiebreakerField' + timestamp_field: + $ref: '#/components/schemas/TimestampField' + EqlQueryLanguage: + enum: + - eql + type: string + EqlRequiredFields: + type: object + properties: + language: + $ref: '#/components/schemas/EqlQueryLanguage' + description: Query language to use + query: + $ref: '#/components/schemas/RuleQuery' + description: EQL query to execute + type: + description: Rule type + enum: + - eql + type: string + required: + - type + - query + - language + EqlRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/EqlRuleResponseFields' + EqlRuleCreateFields: + allOf: + - $ref: '#/components/schemas/EqlRequiredFields' + - $ref: '#/components/schemas/EqlOptionalFields' + EqlRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/EqlRuleCreateFields' + EqlRulePatchFields: + allOf: + - type: object + properties: + language: + $ref: '#/components/schemas/EqlQueryLanguage' + description: Query language to use + query: + $ref: '#/components/schemas/RuleQuery' + description: EQL query to execute + type: + description: Rule type + enum: + - eql + type: string + - $ref: '#/components/schemas/EqlOptionalFields' + EqlRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/EqlRulePatchFields' + EqlRuleResponseFields: + allOf: + - $ref: '#/components/schemas/EqlRequiredFields' + - $ref: '#/components/schemas/EqlOptionalFields' + EqlRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/EqlRuleCreateFields' + ErrorSchema: + additionalProperties: false + type: object + properties: + error: + type: object + properties: + message: + type: string + status_code: + minimum: 400 + type: integer + required: + - status_code + - message + id: + type: string + item_id: + minLength: 1 + type: string + list_id: + minLength: 1 + type: string + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + required: + - error + EsqlQueryLanguage: + enum: + - esql + type: string + EsqlRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/EsqlRuleResponseFields' + EsqlRuleCreateFields: + allOf: + - $ref: '#/components/schemas/EsqlRuleOptionalFields' + - $ref: '#/components/schemas/EsqlRuleRequiredFields' + EsqlRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/EsqlRuleCreateFields' + EsqlRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + EsqlRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + language: + $ref: '#/components/schemas/EsqlQueryLanguage' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + query: + $ref: '#/components/schemas/RuleQuery' + description: ESQL query to execute + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + type: + description: Rule type + enum: + - esql + type: string + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/EsqlRuleOptionalFields' + EsqlRuleRequiredFields: + type: object + properties: + language: + $ref: '#/components/schemas/EsqlQueryLanguage' + query: + $ref: '#/components/schemas/RuleQuery' + description: ESQL query to execute + type: + description: Rule type + enum: + - esql + type: string + required: + - type + - language + - query + EsqlRuleResponseFields: + allOf: + - $ref: '#/components/schemas/EsqlRuleOptionalFields' + - $ref: '#/components/schemas/EsqlRuleRequiredFields' + EsqlRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/EsqlRuleCreateFields' + EventCategoryOverride: + type: string + ExceptionListType: + description: The exception type + enum: + - detection + - rule_default + - endpoint + - endpoint_trusted_apps + - endpoint_events + - endpoint_host_isolation_exceptions + - endpoint_blocklists + type: string + ExternalRuleSource: + description: >- + Type of rule source for externally sourced rules, i.e. rules that have + an external source, such as the Elastic Prebuilt rules repo. + type: object + properties: + is_customized: + $ref: '#/components/schemas/IsExternalRuleCustomized' + type: + enum: + - external + type: string + required: + - type + - is_customized + FindRulesSortField: + enum: + - created_at + - createdAt + - enabled + - execution_summary.last_execution.date + - execution_summary.last_execution.metrics.execution_gap_duration_s + - execution_summary.last_execution.metrics.total_indexing_duration_ms + - execution_summary.last_execution.metrics.total_search_duration_ms + - execution_summary.last_execution.status + - name + - risk_score + - riskScore + - severity + - updated_at + - updatedAt + type: string + HistoryWindowStart: + $ref: '#/components/schemas/NonEmptyString' + IndexPatternArray: + items: + type: string + type: array + InternalRuleSource: + description: >- + Type of rule source for internally sourced rules, i.e. created within + the Kibana apps. + type: object + properties: + type: + enum: + - internal + type: string + required: + - type + InvestigationFields: + type: object + properties: + field_names: + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + required: + - field_names + InvestigationGuide: + description: Notes to help investigate alerts produced by the rule. + type: string + IsExternalRuleCustomized: + description: >- + Determines whether an external/prebuilt rule has been customized by the + user (i.e. any of its fields have been modified and diverged from the + base value). + type: boolean + IsRuleEnabled: + description: Determines whether the rule is enabled. + type: boolean + IsRuleImmutable: + deprecated: true + description: >- + This field determines whether the rule is a prebuilt Elastic rule. It + will be replaced with the `rule_source` field. + type: boolean + ItemsPerSearch: + minimum: 1 + type: integer + KqlQueryLanguage: + enum: + - kuery + - lucene + type: string + MachineLearningJobId: + description: Machine learning job ID + oneOf: + - type: string + - items: + type: string + minItems: 1 + type: array + MachineLearningRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/MachineLearningRuleResponseFields' + MachineLearningRuleCreateFields: + $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + MachineLearningRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/MachineLearningRuleCreateFields' + MachineLearningRulePatchFields: + type: object + properties: + anomaly_threshold: + $ref: '#/components/schemas/AnomalyThreshold' + machine_learning_job_id: + $ref: '#/components/schemas/MachineLearningJobId' + type: + description: Rule type + enum: + - machine_learning + type: string + MachineLearningRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/MachineLearningRulePatchFields' + MachineLearningRuleRequiredFields: + type: object + properties: + anomaly_threshold: + $ref: '#/components/schemas/AnomalyThreshold' + machine_learning_job_id: + $ref: '#/components/schemas/MachineLearningJobId' + type: + description: Rule type + enum: + - machine_learning + type: string + required: + - type + - machine_learning_job_id + - anomaly_threshold + MachineLearningRuleResponseFields: + $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + MachineLearningRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/MachineLearningRuleCreateFields' + MaxSignals: + minimum: 1 + type: integer + NewTermsFields: + items: + type: string + maxItems: 3 + minItems: 1 + type: array + NewTermsRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/NewTermsRuleResponseFields' + NewTermsRuleCreateFields: + allOf: + - $ref: '#/components/schemas/NewTermsRuleRequiredFields' + - $ref: '#/components/schemas/NewTermsRuleOptionalFields' + - $ref: '#/components/schemas/NewTermsRuleDefaultableFields' + NewTermsRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/NewTermsRuleCreateFields' + NewTermsRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + NewTermsRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + NewTermsRulePatchFields: + allOf: + - type: object + properties: + history_window_start: + $ref: '#/components/schemas/HistoryWindowStart' + new_terms_fields: + $ref: '#/components/schemas/NewTermsFields' + query: + $ref: '#/components/schemas/RuleQuery' + type: + description: Rule type + enum: + - new_terms + type: string + - $ref: '#/components/schemas/NewTermsRuleOptionalFields' + - $ref: '#/components/schemas/NewTermsRuleDefaultableFields' + NewTermsRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/NewTermsRulePatchFields' + NewTermsRuleRequiredFields: + type: object + properties: + history_window_start: + $ref: '#/components/schemas/HistoryWindowStart' + new_terms_fields: + $ref: '#/components/schemas/NewTermsFields' + query: + $ref: '#/components/schemas/RuleQuery' + type: + description: Rule type + enum: + - new_terms + type: string + required: + - type + - query + - new_terms_fields + - history_window_start + NewTermsRuleResponseFields: + allOf: + - $ref: '#/components/schemas/NewTermsRuleRequiredFields' + - $ref: '#/components/schemas/NewTermsRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + required: + - language + NewTermsRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/NewTermsRuleCreateFields' + NonEmptyString: + description: A string that is not empty and does not contain only whitespace + minLength: 1 + pattern: ^(?! *$).+$ + type: string + NormalizedRuleAction: + additionalProperties: false + type: object + properties: + alerts_filter: + $ref: '#/components/schemas/RuleActionAlertsFilter' + frequency: + $ref: '#/components/schemas/RuleActionFrequency' + group: + $ref: '#/components/schemas/RuleActionGroup' + id: + $ref: '#/components/schemas/RuleActionId' + params: + $ref: '#/components/schemas/RuleActionParams' + required: + - group + - id + - params + NormalizedRuleError: + type: object + properties: + err_code: + $ref: '#/components/schemas/BulkActionsDryRunErrCode' + message: + type: string + rules: + items: + $ref: '#/components/schemas/RuleDetailsInError' + type: array + status_code: + type: integer + required: + - message + - status_code + - rules + OsqueryParams: + type: object + properties: + ecs_mapping: + $ref: '#/components/schemas/EcsMapping' + pack_id: + type: string + queries: + items: + $ref: '#/components/schemas/OsqueryQuery' + type: array + query: + type: string + saved_query_id: + type: string + timeout: + type: number + OsqueryQuery: + type: object + properties: + ecs_mapping: + $ref: '#/components/schemas/EcsMapping' + id: + description: Query ID + type: string + platform: + type: string + query: + description: Query to execute + type: string + removed: + type: boolean + snapshot: + type: boolean + version: + description: Query version + type: string + required: + - id + - query + OsqueryResponseAction: + type: object + properties: + action_type_id: + enum: + - .osquery + type: string + params: + $ref: '#/components/schemas/OsqueryParams' + required: + - action_type_id + - params + ProcessesParams: + type: object + properties: + command: + enum: + - kill-process + - suspend-process + type: string + comment: + type: string + config: + type: object + properties: + field: + description: Field to use instead of process.pid + type: string + overwrite: + default: true + description: Whether to overwrite field with process.pid + type: boolean + required: + - field + required: + - command + - config + QueryRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/QueryRuleResponseFields' + QueryRuleCreateFields: + allOf: + - $ref: '#/components/schemas/QueryRuleRequiredFields' + - $ref: '#/components/schemas/QueryRuleOptionalFields' + - $ref: '#/components/schemas/QueryRuleDefaultableFields' + QueryRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/QueryRuleCreateFields' + QueryRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + query: + $ref: '#/components/schemas/RuleQuery' + QueryRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array + saved_id: + $ref: '#/components/schemas/SavedQueryId' + QueryRulePatchFields: + allOf: + - type: object + properties: + type: + description: Rule type + enum: + - query + type: string + - $ref: '#/components/schemas/QueryRuleOptionalFields' + - $ref: '#/components/schemas/QueryRuleDefaultableFields' + QueryRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/QueryRulePatchFields' + QueryRuleRequiredFields: + type: object + properties: + type: + description: Rule type + enum: + - query + type: string + required: + - type + QueryRuleResponseFields: + allOf: + - $ref: '#/components/schemas/QueryRuleRequiredFields' + - $ref: '#/components/schemas/QueryRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + query: + $ref: '#/components/schemas/RuleQuery' + required: + - query + - language + QueryRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/QueryRuleCreateFields' + RelatedIntegration: + type: object + properties: + integration: + $ref: '#/components/schemas/NonEmptyString' + package: + $ref: '#/components/schemas/NonEmptyString' + version: + $ref: '#/components/schemas/NonEmptyString' + required: + - package + - version + RelatedIntegrationArray: + items: + $ref: '#/components/schemas/RelatedIntegration' + type: array + RequiredField: + description: Describes an Elasticsearch field that is needed for the rule to function + type: object + properties: + ecs: + description: Whether the field is an ECS field + type: boolean + name: + $ref: '#/components/schemas/NonEmptyString' + description: Name of an Elasticsearch field + type: + $ref: '#/components/schemas/NonEmptyString' + description: Type of the Elasticsearch field + required: + - name + - type + - ecs + RequiredFieldArray: + items: + $ref: '#/components/schemas/RequiredField' + type: array + RequiredFieldInput: + description: >- + Input parameters to create a RequiredField. Does not include the `ecs` + field, because `ecs` is calculated on the backend based on the field + name and type. + type: object + properties: + name: + $ref: '#/components/schemas/NonEmptyString' + description: Name of an Elasticsearch field + type: + $ref: '#/components/schemas/NonEmptyString' + description: Type of an Elasticsearch field + required: + - name + - type + ResponseAction: + oneOf: + - $ref: '#/components/schemas/OsqueryResponseAction' + - $ref: '#/components/schemas/EndpointResponseAction' + ResponseFields: + type: object + properties: + created_at: + format: date-time + type: string + created_by: + type: string + execution_summary: + $ref: '#/components/schemas/RuleExecutionSummary' + id: + $ref: '#/components/schemas/RuleObjectId' + immutable: + $ref: '#/components/schemas/IsRuleImmutable' + required_fields: + $ref: '#/components/schemas/RequiredFieldArray' + revision: + minimum: 0 + type: integer + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_source: + $ref: '#/components/schemas/RuleSource' + updated_at: + format: date-time + type: string + updated_by: + type: string + required: + - id + - rule_id + - immutable + - updated_at + - updated_by + - created_at + - created_by + - revision + - related_integrations + - required_fields + RiskScore: + description: Risk score (0 to 100) + maximum: 100 + minimum: 0 + type: integer + RiskScoreMapping: + description: >- + Overrides generated alerts' risk_score with a value from the source + event + items: + type: object + properties: + field: + type: string + operator: + enum: + - equals + type: string + risk_score: + $ref: '#/components/schemas/RiskScore' + value: + type: string + required: + - field + - operator + - value + type: array + RuleAction: + type: object + properties: + action_type_id: + description: The action type used for sending notifications. + type: string + alerts_filter: + $ref: '#/components/schemas/RuleActionAlertsFilter' + frequency: + $ref: '#/components/schemas/RuleActionFrequency' + group: + $ref: '#/components/schemas/RuleActionGroup' + id: + $ref: '#/components/schemas/RuleActionId' + params: + $ref: '#/components/schemas/RuleActionParams' + uuid: + $ref: '#/components/schemas/NonEmptyString' + required: + - action_type_id + - group + - id + - params + RuleActionAlertsFilter: + additionalProperties: true + type: object + RuleActionFrequency: + description: >- + The action frequency defines when the action runs (for example, only on + rule execution or at specific time intervals). + type: object + properties: + notifyWhen: + $ref: '#/components/schemas/RuleActionNotifyWhen' + summary: + description: >- + Action summary indicates whether we will send a summary notification + about all the generate alerts or notification per individual alert + type: boolean + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + nullable: true + required: + - summary + - notifyWhen + - throttle + RuleActionGroup: + description: >- + Optionally groups actions by use cases. Use `default` for alert + notifications. + type: string + RuleActionId: + description: The connector ID. + type: string + RuleActionNotifyWhen: + description: >- + The condition for throttling the notification: `onActionGroupChange`, + `onActiveAlert`, or `onThrottleInterval` + enum: + - onActiveAlert + - onThrottleInterval + - onActionGroupChange + type: string + RuleActionParams: + additionalProperties: true + description: >- + Object containing the allowed connector fields, which varies according + to the connector type. + type: object + RuleActionThrottle: + description: Defines the interval on which a rule's actions are executed. + oneOf: + - enum: + - no_actions + - rule + type: string + - description: 'Time interval in seconds, minutes, hours, or days.' + example: 1h + pattern: '^[1-9]\d*[smhd]$' + type: string + RuleAuthorArray: + items: + type: string + type: array + RuleCreateProps: + anyOf: + - $ref: '#/components/schemas/EqlRuleCreateProps' + - $ref: '#/components/schemas/QueryRuleCreateProps' + - $ref: '#/components/schemas/SavedQueryRuleCreateProps' + - $ref: '#/components/schemas/ThresholdRuleCreateProps' + - $ref: '#/components/schemas/ThreatMatchRuleCreateProps' + - $ref: '#/components/schemas/MachineLearningRuleCreateProps' + - $ref: '#/components/schemas/NewTermsRuleCreateProps' + - $ref: '#/components/schemas/EsqlRuleCreateProps' + discriminator: + propertyName: type + RuleDescription: + minLength: 1 + type: string + RuleDetailsInError: + type: object + properties: + id: + type: string + name: + type: string + required: + - id + RuleExceptionList: + type: object + properties: + id: + $ref: '#/components/schemas/NonEmptyString' + description: ID of the exception container + list_id: + $ref: '#/components/schemas/NonEmptyString' + description: List ID of the exception container + namespace_type: + description: Determines the exceptions validity in rule's Kibana space + enum: + - agnostic + - single + type: string + type: + $ref: '#/components/schemas/ExceptionListType' + required: + - id + - list_id + - type + - namespace_type + RuleExecutionMetrics: + type: object + properties: + execution_gap_duration_s: + description: Duration in seconds of execution gap + minimum: 0 + type: integer + total_enrichment_duration_ms: + description: >- + Total time spent enriching documents during current rule execution + cycle + minimum: 0 + type: integer + total_indexing_duration_ms: + description: >- + Total time spent indexing documents during current rule execution + cycle + minimum: 0 + type: integer + total_search_duration_ms: + description: >- + Total time spent performing ES searches as measured by Kibana; + includes network latency and time spent serializing/deserializing + request/response + minimum: 0 + type: integer + RuleExecutionStatus: + description: >- + Custom execution status of Security rules that is different from the + status used in the Alerting Framework. We merge our custom status with + the Framework's status to determine the resulting status of a rule. + + - going to run - @deprecated Replaced by the 'running' status but left + for backwards compatibility with rule execution events already written + to Event Log in the prior versions of Kibana. Don't use when writing + rule status changes. + + - running - Rule execution started but not reached any intermediate or + final status. + + - partial failure - Rule can partially fail for various reasons either + in the middle of an execution (in this case we update its status right + away) or in the end of it. So currently this status can be both + intermediate and final at the same time. A typical reason for a partial + failure: not all the indices that the rule searches over actually exist. + + - failed - Rule failed to execute due to unhandled exception or a reason + defined in the business logic of its executor function. + + - succeeded - Rule executed successfully without any issues. Note: this + status is just an indication of a rule's "health". The rule might or + might not generate any alerts despite of it. + enum: + - going to run + - running + - partial failure + - failed + - succeeded + type: string + RuleExecutionStatusOrder: + type: integer + RuleExecutionSummary: + type: object + properties: + last_execution: + type: object + properties: + date: + description: Date of the last execution + format: date-time + type: string + message: + type: string + metrics: + $ref: '#/components/schemas/RuleExecutionMetrics' + status: + $ref: '#/components/schemas/RuleExecutionStatus' + description: Status of the last execution + status_order: + $ref: '#/components/schemas/RuleExecutionStatusOrder' + required: + - date + - status + - status_order + - message + - metrics + required: + - last_execution + RuleFalsePositiveArray: + items: + type: string + type: array + RuleFilterArray: + items: {} + type: array + RuleInterval: + description: >- + Frequency of rule execution, using a date math range. For example, "1h" + means the rule runs every hour. Defaults to 5m (5 minutes). + type: string + RuleIntervalFrom: + description: >- + Time from which data is analyzed each time the rule executes, using a + date math range. For example, now-4200s means the rule analyzes data + from 70 minutes before its start time. Defaults to now-6m (analyzes data + from 6 minutes before the start time). + format: date-math + type: string + RuleIntervalTo: + type: string + RuleLicense: + description: The rule's license. + type: string + RuleMetadata: + additionalProperties: true + type: object + RuleName: + minLength: 1 + type: string + RuleNameOverride: + description: Sets the source field for the alert's signal.rule.name value + type: string + RuleObjectId: + $ref: '#/components/schemas/UUID' + RulePatchProps: + anyOf: + - $ref: '#/components/schemas/EqlRulePatchProps' + - $ref: '#/components/schemas/QueryRulePatchProps' + - $ref: '#/components/schemas/SavedQueryRulePatchProps' + - $ref: '#/components/schemas/ThresholdRulePatchProps' + - $ref: '#/components/schemas/ThreatMatchRulePatchProps' + - $ref: '#/components/schemas/MachineLearningRulePatchProps' + - $ref: '#/components/schemas/NewTermsRulePatchProps' + - $ref: '#/components/schemas/EsqlRulePatchProps' + RuleQuery: + type: string + RuleReferenceArray: + items: + type: string + type: array + RuleResponse: + anyOf: + - $ref: '#/components/schemas/EqlRule' + - $ref: '#/components/schemas/QueryRule' + - $ref: '#/components/schemas/SavedQueryRule' + - $ref: '#/components/schemas/ThresholdRule' + - $ref: '#/components/schemas/ThreatMatchRule' + - $ref: '#/components/schemas/MachineLearningRule' + - $ref: '#/components/schemas/NewTermsRule' + - $ref: '#/components/schemas/EsqlRule' + discriminator: + propertyName: type + RuleSignatureId: + description: 'Could be any string, not necessarily a UUID' + type: string + RuleSource: + description: >- + Discriminated union that determines whether the rule is internally + sourced (created within the Kibana app) or has an external source, such + as the Elastic Prebuilt rules repo. + discriminator: + propertyName: type + oneOf: + - $ref: '#/components/schemas/ExternalRuleSource' + - $ref: '#/components/schemas/InternalRuleSource' + RuleTagArray: + description: >- + String array containing words and phrases to help categorize, filter, + and search rules. Defaults to an empty array. + items: + type: string + type: array + RuleUpdateProps: + anyOf: + - $ref: '#/components/schemas/EqlRuleUpdateProps' + - $ref: '#/components/schemas/QueryRuleUpdateProps' + - $ref: '#/components/schemas/SavedQueryRuleUpdateProps' + - $ref: '#/components/schemas/ThresholdRuleUpdateProps' + - $ref: '#/components/schemas/ThreatMatchRuleUpdateProps' + - $ref: '#/components/schemas/MachineLearningRuleUpdateProps' + - $ref: '#/components/schemas/NewTermsRuleUpdateProps' + - $ref: '#/components/schemas/EsqlRuleUpdateProps' + discriminator: + propertyName: type + RuleVersion: + description: The rule's version number. + minimum: 1 + type: integer + SavedObjectResolveAliasPurpose: + enum: + - savedObjectConversion + - savedObjectImport + type: string + SavedObjectResolveAliasTargetId: + type: string + SavedObjectResolveOutcome: + enum: + - exactMatch + - aliasMatch + - conflict + type: string + SavedQueryId: + type: string + SavedQueryRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/SavedQueryRuleResponseFields' + SavedQueryRuleCreateFields: + allOf: + - $ref: '#/components/schemas/SavedQueryRuleRequiredFields' + - $ref: '#/components/schemas/SavedQueryRuleOptionalFields' + - $ref: '#/components/schemas/SavedQueryRuleDefaultableFields' + SavedQueryRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/SavedQueryRuleCreateFields' + SavedQueryRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + SavedQueryRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + query: + $ref: '#/components/schemas/RuleQuery' + response_actions: + items: + $ref: '#/components/schemas/ResponseAction' + type: array + SavedQueryRulePatchFields: + allOf: + - type: object + properties: + saved_id: + $ref: '#/components/schemas/SavedQueryId' + type: + description: Rule type + enum: + - saved_query + type: string + - $ref: '#/components/schemas/SavedQueryRuleOptionalFields' + - $ref: '#/components/schemas/SavedQueryRuleDefaultableFields' + SavedQueryRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/SavedQueryRulePatchFields' + SavedQueryRuleRequiredFields: + type: object + properties: + saved_id: + $ref: '#/components/schemas/SavedQueryId' + type: + description: Rule type + enum: + - saved_query + type: string + required: + - type + - saved_id + SavedQueryRuleResponseFields: + allOf: + - $ref: '#/components/schemas/SavedQueryRuleRequiredFields' + - $ref: '#/components/schemas/SavedQueryRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + required: + - language + SavedQueryRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/SavedQueryRuleCreateFields' + SetupGuide: + type: string + Severity: + description: Severity of the rule + enum: + - low + - medium + - high + - critical + type: string + SeverityMapping: + description: Overrides generated alerts' severity with values from the source event + items: + type: object + properties: + field: + type: string + operator: + enum: + - equals + type: string + severity: + $ref: '#/components/schemas/Severity' + value: + type: string + required: + - field + - operator + - severity + - value + type: array + SortOrder: + enum: + - asc + - desc + type: string + Threat: + type: object + properties: + framework: + description: Relevant attack framework + type: string + tactic: + $ref: '#/components/schemas/ThreatTactic' + technique: + description: Array containing information on the attack techniques (optional) + items: + $ref: '#/components/schemas/ThreatTechnique' + type: array + required: + - framework + - tactic + ThreatArray: + items: + $ref: '#/components/schemas/Threat' + type: array + ThreatFilters: + items: + description: >- + Query and filter context array used to filter documents from the + Elasticsearch index containing the threat values + type: array + ThreatIndex: + items: + type: string + type: array + ThreatIndicatorPath: + description: >- + Defines the path to the threat indicator in the indicator documents + (optional) + type: string + ThreatMapping: + items: + type: object + properties: + entries: + items: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + type: + enum: + - mapping + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - field + - type + - value + type: array + required: + - entries + minItems: 1 + type: array + ThreatMatchRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/ThreatMatchRuleResponseFields' + ThreatMatchRuleCreateFields: + allOf: + - $ref: '#/components/schemas/ThreatMatchRuleRequiredFields' + - $ref: '#/components/schemas/ThreatMatchRuleOptionalFields' + - $ref: '#/components/schemas/ThreatMatchRuleDefaultableFields' + ThreatMatchRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/ThreatMatchRuleCreateFields' + ThreatMatchRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + ThreatMatchRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + concurrent_searches: + $ref: '#/components/schemas/ConcurrentSearches' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + items_per_search: + $ref: '#/components/schemas/ItemsPerSearch' + saved_id: + $ref: '#/components/schemas/SavedQueryId' + threat_filters: + $ref: '#/components/schemas/ThreatFilters' + threat_indicator_path: + $ref: '#/components/schemas/ThreatIndicatorPath' + threat_language: + $ref: '#/components/schemas/KqlQueryLanguage' + ThreatMatchRulePatchFields: + allOf: + - type: object + properties: + query: + $ref: '#/components/schemas/RuleQuery' + threat_index: + $ref: '#/components/schemas/ThreatIndex' + threat_mapping: + $ref: '#/components/schemas/ThreatMapping' + threat_query: + $ref: '#/components/schemas/ThreatQuery' + type: + description: Rule type + enum: + - threat_match + type: string + - $ref: '#/components/schemas/ThreatMatchRuleOptionalFields' + - $ref: '#/components/schemas/ThreatMatchRuleDefaultableFields' + ThreatMatchRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/ThreatMatchRulePatchFields' + ThreatMatchRuleRequiredFields: + type: object + properties: + query: + $ref: '#/components/schemas/RuleQuery' + threat_index: + $ref: '#/components/schemas/ThreatIndex' + threat_mapping: + $ref: '#/components/schemas/ThreatMapping' + threat_query: + $ref: '#/components/schemas/ThreatQuery' + type: + description: Rule type + enum: + - threat_match + type: string + required: + - type + - query + - threat_query + - threat_mapping + - threat_index + ThreatMatchRuleResponseFields: + allOf: + - $ref: '#/components/schemas/ThreatMatchRuleRequiredFields' + - $ref: '#/components/schemas/ThreatMatchRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + required: + - language + ThreatMatchRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/ThreatMatchRuleCreateFields' + ThreatQuery: + description: Query to execute + type: string + ThreatSubtechnique: + type: object + properties: + id: + description: Subtechnique ID + type: string + name: + description: Subtechnique name + type: string + reference: + description: Subtechnique reference + type: string + required: + - id + - name + - reference + ThreatTactic: + type: object + properties: + id: + description: Tactic ID + type: string + name: + description: Tactic name + type: string + reference: + description: Tactic reference + type: string + required: + - id + - name + - reference + ThreatTechnique: + type: object + properties: + id: + description: Technique ID + type: string + name: + description: Technique name + type: string + reference: + description: Technique reference + type: string + subtechnique: + description: Array containing more specific information on the attack technique + items: + $ref: '#/components/schemas/ThreatSubtechnique' + type: array + required: + - id + - name + - reference + Threshold: + type: object + properties: + cardinality: + $ref: '#/components/schemas/ThresholdCardinality' + field: + $ref: '#/components/schemas/ThresholdField' + value: + $ref: '#/components/schemas/ThresholdValue' + required: + - field + - value + ThresholdAlertSuppression: + type: object + properties: + duration: + $ref: '#/components/schemas/AlertSuppressionDuration' + required: + - duration + ThresholdCardinality: + items: + type: object + properties: + field: + type: string + value: + minimum: 0 + type: integer + required: + - field + - value + type: array + ThresholdField: + description: Field to aggregate on + oneOf: + - type: string + - items: + type: string + type: array + ThresholdRule: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - version + - tags + - enabled + - risk_score_mapping + - severity_mapping + - interval + - from + - to + - actions + - exceptions_list + - author + - false_positives + - references + - max_signals + - threat + - setup + - related_integrations + - required_fields + - $ref: '#/components/schemas/ResponseFields' + - $ref: '#/components/schemas/ThresholdRuleResponseFields' + ThresholdRuleCreateFields: + allOf: + - $ref: '#/components/schemas/ThresholdRuleRequiredFields' + - $ref: '#/components/schemas/ThresholdRuleOptionalFields' + - $ref: '#/components/schemas/ThresholdRuleDefaultableFields' + ThresholdRuleCreateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/ThresholdRuleCreateFields' + ThresholdRuleDefaultableFields: + type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + ThresholdRuleOptionalFields: + type: object + properties: + alert_suppression: + $ref: '#/components/schemas/ThresholdAlertSuppression' + data_view_id: + $ref: '#/components/schemas/DataViewId' + filters: + $ref: '#/components/schemas/RuleFilterArray' + index: + $ref: '#/components/schemas/IndexPatternArray' + saved_id: + $ref: '#/components/schemas/SavedQueryId' + ThresholdRulePatchFields: + allOf: + - type: object + properties: + query: + $ref: '#/components/schemas/RuleQuery' + threshold: + $ref: '#/components/schemas/Threshold' + type: + description: Rule type + enum: + - threshold + type: string + - $ref: '#/components/schemas/ThresholdRuleOptionalFields' + - $ref: '#/components/schemas/ThresholdRuleDefaultableFields' + ThresholdRulePatchProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + - $ref: '#/components/schemas/ThresholdRulePatchFields' + ThresholdRuleRequiredFields: + type: object + properties: + query: + $ref: '#/components/schemas/RuleQuery' + threshold: + $ref: '#/components/schemas/Threshold' + type: + description: Rule type + enum: + - threshold + type: string + required: + - type + - query + - threshold + ThresholdRuleResponseFields: + allOf: + - $ref: '#/components/schemas/ThresholdRuleRequiredFields' + - $ref: '#/components/schemas/ThresholdRuleOptionalFields' + - type: object + properties: + language: + $ref: '#/components/schemas/KqlQueryLanguage' + required: + - language + ThresholdRuleUpdateProps: + allOf: + - type: object + properties: + actions: + items: + $ref: '#/components/schemas/RuleAction' + type: array + alias_purpose: + $ref: '#/components/schemas/SavedObjectResolveAliasPurpose' + alias_target_id: + $ref: '#/components/schemas/SavedObjectResolveAliasTargetId' + author: + $ref: '#/components/schemas/RuleAuthorArray' + building_block_type: + $ref: '#/components/schemas/BuildingBlockType' + description: + $ref: '#/components/schemas/RuleDescription' + enabled: + $ref: '#/components/schemas/IsRuleEnabled' + exceptions_list: + items: + $ref: '#/components/schemas/RuleExceptionList' + type: array + false_positives: + $ref: '#/components/schemas/RuleFalsePositiveArray' + from: + $ref: '#/components/schemas/RuleIntervalFrom' + id: + $ref: '#/components/schemas/RuleObjectId' + interval: + $ref: '#/components/schemas/RuleInterval' + investigation_fields: + $ref: '#/components/schemas/InvestigationFields' + license: + $ref: '#/components/schemas/RuleLicense' + max_signals: + $ref: '#/components/schemas/MaxSignals' + meta: + $ref: '#/components/schemas/RuleMetadata' + name: + $ref: '#/components/schemas/RuleName' + namespace: + $ref: '#/components/schemas/AlertsIndexNamespace' + note: + $ref: '#/components/schemas/InvestigationGuide' + outcome: + $ref: '#/components/schemas/SavedObjectResolveOutcome' + output_index: + $ref: '#/components/schemas/AlertsIndex' + references: + $ref: '#/components/schemas/RuleReferenceArray' + related_integrations: + $ref: '#/components/schemas/RelatedIntegrationArray' + required_fields: + items: + $ref: '#/components/schemas/RequiredFieldInput' + type: array + risk_score: + $ref: '#/components/schemas/RiskScore' + risk_score_mapping: + $ref: '#/components/schemas/RiskScoreMapping' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + rule_name_override: + $ref: '#/components/schemas/RuleNameOverride' + setup: + $ref: '#/components/schemas/SetupGuide' + severity: + $ref: '#/components/schemas/Severity' + severity_mapping: + $ref: '#/components/schemas/SeverityMapping' + tags: + $ref: '#/components/schemas/RuleTagArray' + threat: + $ref: '#/components/schemas/ThreatArray' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + timeline_id: + $ref: '#/components/schemas/TimelineTemplateId' + timeline_title: + $ref: '#/components/schemas/TimelineTemplateTitle' + timestamp_override: + $ref: '#/components/schemas/TimestampOverride' + timestamp_override_fallback_disabled: + $ref: '#/components/schemas/TimestampOverrideFallbackDisabled' + to: + $ref: '#/components/schemas/RuleIntervalTo' + version: + $ref: '#/components/schemas/RuleVersion' + required: + - name + - description + - risk_score + - severity + - $ref: '#/components/schemas/ThresholdRuleCreateFields' + ThresholdValue: + description: Threshold value + minimum: 1 + type: integer + ThrottleForBulkActions: + description: >- + The condition for throttling the notification: 'rule', 'no_actions', or + time duration + enum: + - rule + - 1h + - 1d + - 7d + type: string + TiebreakerField: + description: Sets a secondary field for sorting events + type: string + TimelineTemplateId: + description: Timeline template ID + type: string + TimelineTemplateTitle: + description: Timeline template title + type: string + TimestampField: + description: Contains the event timestamp used for sorting a sequence of events + type: string + TimestampOverride: + description: Sets the time field used to query indices + type: string + TimestampOverrideFallbackDisabled: + description: Disables the fallback to the event's @timestamp field + type: boolean + UUID: + description: A universally unique identifier + format: uuid + type: string + WarningSchema: + type: object + properties: + actionPath: + type: string + buttonLabel: + type: string + message: + type: string + type: + type: string + required: + - type + - message + - actionPath + securitySchemes: + BasicAuth: + scheme: basic + type: http +security: + - BasicAuth: [] diff --git a/x-pack/plugins/security_solution/scripts/openapi/bundle.js b/x-pack/plugins/security_solution/scripts/openapi/bundle.js index cba548cfd29039..e2df0d47f5b47f 100644 --- a/x-pack/plugins/security_solution/scripts/openapi/bundle.js +++ b/x-pack/plugins/security_solution/scripts/openapi/bundle.js @@ -9,26 +9,36 @@ require('../../../../../src/setup_node_env'); const { bundle } = require('@kbn/openapi-bundler'); const { join, resolve } = require('path'); -const SECURITY_SOLUTION_ROOT = resolve(__dirname, '../..'); +const ROOT = resolve(__dirname, '../..'); bundle({ - sourceGlob: join(SECURITY_SOLUTION_ROOT, 'common/api/**/*.schema.yaml'), + sourceGlob: join(ROOT, 'common/api/detection_engine/**/*.schema.yaml'), outputFilePath: join( - SECURITY_SOLUTION_ROOT, - 'target/openapi/serverless/security_solution-{version}.bundled.schema.yaml' + ROOT, + 'docs/openapi/serverless/security_solution_detections_api_{version}.bundled.schema.yaml' ), options: { includeLabels: ['serverless'], + specInfo: { + title: 'Security Solution Detections API (Elastic Cloud Serverless)', + description: + 'You can create rules that automatically turn events and external alerts sent to Elastic Security into detection alerts. These alerts are displayed on the Detections page.', + }, }, }); bundle({ - sourceGlob: join(SECURITY_SOLUTION_ROOT, 'common/api/**/*.schema.yaml'), + sourceGlob: join(ROOT, 'common/api/detection_engine/**/*.schema.yaml'), outputFilePath: join( - SECURITY_SOLUTION_ROOT, - 'target/openapi/ess/security_solution-{version}.bundled.schema.yaml' + ROOT, + 'docs/openapi/ess/security_solution_detections_api_{version}.bundled.schema.yaml' ), options: { includeLabels: ['ess'], + specInfo: { + title: 'Security Solution Detections API (Elastic Cloud and self-hosted)', + description: + 'You can create rules that automatically turn events and external alerts sent to Elastic Security into detection alerts. These alerts are displayed on the Detections page.', + }, }, }); diff --git a/x-pack/plugins/security_solution/scripts/openapi/generate.js b/x-pack/plugins/security_solution/scripts/openapi/generate.js index d4484c1f714616..38eb0fe06f95ae 100644 --- a/x-pack/plugins/security_solution/scripts/openapi/generate.js +++ b/x-pack/plugins/security_solution/scripts/openapi/generate.js @@ -16,7 +16,7 @@ const SECURITY_SOLUTION_ROOT = resolve(__dirname, '../..'); await generate({ title: 'API route schemas', rootDir: SECURITY_SOLUTION_ROOT, - sourceGlob: './**/*.schema.yaml', + sourceGlob: './common/**/*.schema.yaml', templateName: 'zod_operation_schema', skipLinting: true, }); @@ -24,7 +24,7 @@ const SECURITY_SOLUTION_ROOT = resolve(__dirname, '../..'); await generate({ title: 'API client for tests', rootDir: SECURITY_SOLUTION_ROOT, - sourceGlob: './**/*.schema.yaml', + sourceGlob: './common/**/*.schema.yaml', templateName: 'api_client_supertest', skipLinting: true, bundle: { From d2325ce927b97c5153b7955bbc33c233f68e88c0 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 18 Jun 2024 21:39:32 +0100 Subject: [PATCH 061/123] skip flaky suite (#186315) --- .../pages/cis_integrations/kspm/cis_integration_eks.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts index db0778831964f5..3d115fd33f8bf0 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts @@ -50,7 +50,8 @@ export default function (providerContext: FtrProviderContext) { }); }); - describe('KSPM EKS Direct Access', async () => { + // FLAKY: https://github.com/elastic/kibana/issues/186315 + describe.skip('KSPM EKS Direct Access', async () => { it('KSPM EKS Direct Access Workflow', async () => { const directAccessKeyId = 'directAccessKeyIdTest'; const directAccessSecretKey = 'directAccessSecretKeyTest'; From 141044e51ec77ea7c5e68c9311a381aecb515497 Mon Sep 17 00:00:00 2001 From: Sander Philipse <94373878+sphilipse@users.noreply.github.com> Date: Tue, 18 Jun 2024 23:35:24 +0200 Subject: [PATCH 062/123] [Search] Fix search index rerendering unnecessarily (#186412) ## Summary This fixes the search index rerendering on every change, even if nothing actually changed. --- .../components/search_index/search_index.tsx | 81 ++++++++++++------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx index 09e6b494f94e4b..7c13a3f524ccf3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useEffect } from 'react'; +import React, { useEffect, useMemo } from 'react'; import { useParams } from 'react-router-dom'; @@ -15,12 +15,15 @@ import { EuiTabbedContent, EuiTabbedContentTab } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { ClientConfigType } from '../../../../../common/types'; + import { generateEncodedPath } from '../../../shared/encode_path_params'; import { ErrorStatePrompt } from '../../../shared/error_state'; import { HttpLogic } from '../../../shared/http'; import { KibanaLogic } from '../../../shared/kibana'; import { SEARCH_INDEX_PATH, SEARCH_INDEX_TAB_PATH } from '../../routes'; +import { ElasticsearchViewIndex } from '../../types'; import { isConnectorIndex, isCrawlerIndex } from '../../utils/indices'; import { ConnectorConfiguration } from '../connector_detail/connector_configuration'; import { EnterpriseSearchContentPageTemplate } from '../layout/page_template'; @@ -223,20 +226,6 @@ export const SearchIndex: React.FC = () => { ...(hasDefaultIngestPipeline ? [PIPELINES_TAB] : []), ]; - const selectedTab = tabs.find((tab) => tab.id === tabId); - - const onTabClick = (tab: EuiTabbedContentTab) => { - KibanaLogic.values.navigateToUrl( - generateEncodedPath( - tab.id === SearchIndexTabId.OVERVIEW ? SEARCH_INDEX_PATH : SEARCH_INDEX_TAB_PATH, - { - indexName, - tabId: tab.id, - } - ) - ); - }; - return ( { rightSideItems: getHeaderActions(index), }} > - {isCrawlerIndex(index) && !index.connector ? ( - - ) : isCrawlerIndex(index) && (Boolean(errorConnectingMessage) || !config.host) ? ( - - ) : ( - <> - {indexName === index?.name && ( - - )} - {isCrawlerIndex(index) && } - - )} + ); }; + +interface ContentProps { + config?: ClientConfigType; + errorConnectingMessage: string; + index?: ElasticsearchViewIndex; + tabId?: string; + tabs: EuiTabbedContentTab[]; +} + +const Content: React.FC = ({ + config, + errorConnectingMessage, + index, + tabs, + tabId, +}) => { + const selectedTab = useMemo(() => tabs.find((tab) => tab.id === tabId), [tabId]); + + const onTabClick = (tab: EuiTabbedContentTab) => { + KibanaLogic.values.navigateToUrl( + generateEncodedPath( + tab.id === SearchIndexTabId.OVERVIEW ? SEARCH_INDEX_PATH : SEARCH_INDEX_TAB_PATH, + { + indexName: index?.name || '', + tabId: tab.id, + } + ) + ); + }; + + if (isCrawlerIndex(index) && !index.connector) { + return ; + } + if (isCrawlerIndex(index) && (Boolean(errorConnectingMessage) || !config?.host)) { + return ; + } + return ( + <> + + {isCrawlerIndex(index) && } + + ); +}; From 0dd4f9b8c76f467b8e327b64d70b43560a9f8642 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Wed, 19 Jun 2024 00:13:13 +0200 Subject: [PATCH 063/123] Un-revert "Siem query rule - reduce field_caps usage" (#186317) ## Summary https://github.com/elastic/kibana/pull/184890 was reverted in https://github.com/elastic/kibana/pull/186196 because it contained a bug with alerts created using Lucene queries. The bug was fixed in https://github.com/elastic/kibana/pull/186217. This PR un-reverts the original changes and preserves the fix. It also adds unit tests to cover the failed cases. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../data/common/search/search_source/index.ts | 1 + .../search_source/query_to_fields.test.ts | 82 +++++++++++++++++++ .../search/search_source/query_to_fields.ts | 58 +++++++++++++ .../search/search_source/search_source.ts | 41 +--------- .../rule_types/__mocks__/rule_type.ts | 8 ++ .../create_security_rule_type_wrapper.ts | 9 +- .../rule_types/query/query.ts | 1 + .../rule_types/utils/get_filter.ts | 8 +- .../utils/get_query_filter_load_fields.ts | 67 +++++++++++++++ 9 files changed, 234 insertions(+), 41 deletions(-) create mode 100644 src/plugins/data/common/search/search_source/query_to_fields.test.ts create mode 100644 src/plugins/data/common/search/search_source/query_to_fields.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_query_filter_load_fields.ts diff --git a/src/plugins/data/common/search/search_source/index.ts b/src/plugins/data/common/search/search_source/index.ts index 189538415ab537..0bc25a0fe85d00 100644 --- a/src/plugins/data/common/search/search_source/index.ts +++ b/src/plugins/data/common/search/search_source/index.ts @@ -15,3 +15,4 @@ export * from './fetch'; export * from './search_source'; export * from './search_source_service'; export * from './types'; +export * from './query_to_fields'; diff --git a/src/plugins/data/common/search/search_source/query_to_fields.test.ts b/src/plugins/data/common/search/search_source/query_to_fields.test.ts new file mode 100644 index 00000000000000..b7ed2f6f123331 --- /dev/null +++ b/src/plugins/data/common/search/search_source/query_to_fields.test.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 { EsQuerySortValue, queryToFields, SearchRequest, SortDirection } from '../..'; +import { DataViewLazy } from '@kbn/data-views-plugin/common'; + +describe('SearchSource#queryToFields', () => { + it('should include time field', async () => { + const dataView = { + timeFieldName: '@timestamp', + getSourceFiltering: jest.fn(), + getFields: jest.fn().mockResolvedValue({ + getFieldMapSorted: jest.fn(), + }), + }; + const request: SearchRequest = { query: [] }; + await queryToFields({ dataView: dataView as unknown as DataViewLazy, request }); + const { fieldName } = dataView.getFields.mock.calls[0][0]; + expect(fieldName).toEqual(['@timestamp']); + }); + + it('should include sort field', async () => { + const dataView = { + getSourceFiltering: jest.fn(), + getFields: jest.fn().mockResolvedValue({ + getFieldMapSorted: jest.fn(), + }), + }; + const sort: EsQuerySortValue = { bytes: SortDirection.asc }; + const request: SearchRequest = { query: [] }; + await queryToFields({ dataView: dataView as unknown as DataViewLazy, sort, request }); + const { fieldName } = dataView.getFields.mock.calls[0][0]; + expect(fieldName).toEqual(['bytes']); + }); + + it('should include request KQL query fields', async () => { + const dataView = { + timeFieldName: '@timestamp', + getSourceFiltering: jest.fn(), + getFields: jest.fn().mockResolvedValue({ + getFieldMapSorted: jest.fn(), + }), + }; + const request: SearchRequest = { + query: [ + { + language: 'kuery', + query: 'log.level: debug AND NOT message: unknown', + }, + ], + }; + await queryToFields({ dataView: dataView as unknown as DataViewLazy, request }); + const { fieldName } = dataView.getFields.mock.calls[0][0]; + expect(fieldName).toEqual(['@timestamp', 'log.level', 'message']); + }); + + it('should not include request Lucene query fields', async () => { + const dataView = { + timeFieldName: '@timestamp', + getSourceFiltering: jest.fn(), + getFields: jest.fn().mockResolvedValue({ + getFieldMapSorted: jest.fn(), + }), + }; + const request: SearchRequest = { + query: [ + { + language: 'lucene', + query: 'host: artifacts\\.*', + }, + ], + }; + await queryToFields({ dataView: dataView as unknown as DataViewLazy, request }); + const { fieldName } = dataView.getFields.mock.calls[0][0]; + expect(fieldName).toEqual(['@timestamp']); + }); +}); diff --git a/src/plugins/data/common/search/search_source/query_to_fields.ts b/src/plugins/data/common/search/search_source/query_to_fields.ts new file mode 100644 index 00000000000000..ebae3354dcea92 --- /dev/null +++ b/src/plugins/data/common/search/search_source/query_to_fields.ts @@ -0,0 +1,58 @@ +/* + * 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 { DataViewLazy } from '@kbn/data-views-plugin/common'; +import { fromKueryExpression, getKqlFieldNames } from '@kbn/es-query'; +import type { SearchRequest } from './fetch'; +import { EsQuerySortValue } from '../..'; + +export async function queryToFields({ + dataView, + sort, + request, +}: { + dataView: DataViewLazy; + sort?: EsQuerySortValue | EsQuerySortValue[]; + request: SearchRequest; +}) { + let fields = dataView.timeFieldName ? [dataView.timeFieldName] : []; + if (sort) { + const sortArr = Array.isArray(sort) ? sort : [sort]; + fields.push(...sortArr.flatMap((s) => Object.keys(s))); + } + for (const query of request.query) { + if (query.query && query.language === 'kuery') { + const nodes = fromKueryExpression(query.query); + const queryFields = getKqlFieldNames(nodes); + fields = fields.concat(queryFields); + } + } + const filters = request.filters; + if (filters) { + const filtersArr = Array.isArray(filters) ? filters : [filters]; + for (const f of filtersArr) { + // unified search bar filters have meta object and key (regular filters) + // unified search bar "custom" filters ("Edit as query DSL", where meta.key is not present but meta is) + // Any other Elasticsearch query DSL filter that gets passed in by consumers (not coming from unified search, and these probably won't have a meta key at all) + if (f?.meta?.key && f.meta.disabled !== true) { + fields.push(f.meta.key); + } + } + } + + // if source filtering is enabled, we need to fetch all the fields + const fieldName = + dataView.getSourceFiltering() && dataView.getSourceFiltering().excludes.length ? ['*'] : fields; + + if (fieldName.length) { + return (await dataView.getFields({ fieldName })).getFieldMapSorted(); + } + + // no fields needed to be loaded for query + return {}; +} diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index 0989251a3b50c8..a5009f350bd3a5 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -77,11 +77,9 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { buildEsQuery, Filter, - fromKueryExpression, isOfQueryType, isPhraseFilter, isPhrasesFilter, - getKqlFieldNames, } from '@kbn/es-query'; import { fieldWildcardFilter } from '@kbn/kibana-utils-plugin/common'; import { getHighlightRequest } from '@kbn/field-formats-plugin/common'; @@ -95,6 +93,7 @@ import type { ISearchGeneric, IKibanaSearchResponse, IEsSearchResponse } from '@ import { normalizeSortRequest } from './normalize_sort_request'; import { AggConfigSerialized, DataViewField, SerializedSearchSourceFields } from '../..'; +import { queryToFields } from './query_to_fields'; import { AggConfigs, EsQuerySortValue } from '../..'; import type { @@ -778,43 +777,7 @@ export class SearchSource { public async loadDataViewFields(dataView: DataViewLazy) { const request = this.mergeProps(this, { body: {} }); - let fields = dataView.timeFieldName ? [dataView.timeFieldName] : []; - const sort = this.getField('sort'); - if (sort) { - const sortArr = Array.isArray(sort) ? sort : [sort]; - for (const s of sortArr) { - const keys = Object.keys(s); - fields = fields.concat(keys); - } - } - for (const query of request.query) { - if (query.query && query.language === 'kuery') { - const nodes = fromKueryExpression(query.query); - const queryFields = getKqlFieldNames(nodes); - fields = fields.concat(queryFields); - } - } - const filters = request.filters; - if (filters) { - const filtersArr = Array.isArray(filters) ? filters : [filters]; - for (const f of filtersArr) { - fields = fields.concat(f.meta.key); - } - } - fields = fields.filter((f) => Boolean(f)); - - if (dataView.getSourceFiltering() && dataView.getSourceFiltering().excludes.length) { - // if source filtering is enabled, we need to fetch all the fields - return (await dataView.getFields({ fieldName: ['*'] })).getFieldMapSorted(); - } else if (fields.length) { - return ( - await dataView.getFields({ - fieldName: fields, - }) - ).getFieldMapSorted(); - } - // no fields needed to be loaded for query - return {}; + return await queryToFields({ dataView, request }); } private flatten() { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts index 6a863728cd7463..6cf237ca583e2d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts @@ -104,6 +104,14 @@ export const createRuleTypeMocks = ( alertWithPersistence: jest.fn(), logger: loggerMock, shouldWriteAlerts: () => true, + dataViews: { + createDataViewLazy: jest.fn().mockResolvedValue({ + getFields: jest.fn().mockResolvedValue({ + getFieldMapSorted: jest.fn().mockReturnValue({}), + }), + getSourceFiltering: jest.fn().mockReturnValue({ excludes: [] }), + }), + }, }; return { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts index 72caa1d61ff638..471087fa77a4a3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts @@ -26,6 +26,8 @@ import { hasTimestampFields, isMachineLearningParams, isEsqlParams, + isQueryParams, + isEqlParams, getDisabledActionsWarningText, } from './utils/utils'; import { DEFAULT_MAX_SIGNALS, DEFAULT_SEARCH_AFTER_PAGE_SIZE } from '../../../../common/constants'; @@ -341,7 +343,12 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = }); } - if (!isMachineLearningParams(params) && !isEsqlParams(params)) { + if ( + !isMachineLearningParams(params) && + !isEsqlParams(params) && + !isQueryParams(params) && + !isEqlParams(params) + ) { inputIndexFields = await getFieldsForWildcard({ index: inputIndex, dataViews: services.dataViews, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts index b3de5a39d829fb..272184dbf1e58c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/query.ts @@ -59,6 +59,7 @@ export const queryExecutor = async ({ index: runOpts.inputIndex, exceptionFilter: runOpts.exceptionFilter, fields: runOpts.inputIndexFields, + loadFields: true, }); const license = await firstValueFrom(licensing.license$); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_filter.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_filter.ts index 7d7492bd17e2b5..920e2c2df9c5e5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_filter.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_filter.ts @@ -26,7 +26,8 @@ import type { SavedIdOrUndefined } from '../../../../../common/api/detection_eng import type { PartialFilter } from '../../types'; import { withSecuritySpan } from '../../../../utils/with_security_span'; import type { ESBoolQuery } from '../../../../../common/typed_json'; -import { getQueryFilter } from './get_query_filter'; +import { getQueryFilter as getQueryFilterNoLoadFields } from './get_query_filter'; +import { getQueryFilterLoadFields } from './get_query_filter_load_fields'; export interface GetFilterArgs { type: Type; @@ -38,6 +39,7 @@ export interface GetFilterArgs { index: IndexPatternArray | undefined; exceptionFilter: Filter | undefined; fields?: DataViewFieldBase[]; + loadFields?: boolean; } interface QueryAttributes { @@ -59,7 +61,11 @@ export const getFilter = async ({ query, exceptionFilter, fields = [], + loadFields = false, }: GetFilterArgs): Promise => { + const getQueryFilter = loadFields + ? getQueryFilterLoadFields(services.dataViews) + : getQueryFilterNoLoadFields; const queryFilter = () => { if (query != null && language != null && index != null) { return getQueryFilter({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_query_filter_load_fields.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_query_filter_load_fields.ts new file mode 100644 index 00000000000000..d1c8eab7ac2c29 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/get_query_filter_load_fields.ts @@ -0,0 +1,67 @@ +/* + * 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 { Language } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { Filter, EsQueryConfig, DataViewFieldBase } from '@kbn/es-query'; +import { DataView } from '@kbn/data-views-plugin/server'; +import { queryToFields } from '@kbn/data-plugin/common'; +import type { DataViewsContract } from '@kbn/data-views-plugin/common'; +import type { FieldFormatsStartCommon } from '@kbn/field-formats-plugin/common'; +import { buildEsQuery } from '@kbn/es-query'; +import type { ESBoolQuery } from '../../../../../common/typed_json'; +import { getAllFilters } from './get_query_filter'; +import type { + IndexPatternArray, + RuleQuery, +} from '../../../../../common/api/detection_engine/model/rule_schema'; + +export const getQueryFilterLoadFields = + (dataViewsService: DataViewsContract) => + async ({ + query, + language, + filters, + index, + exceptionFilter, + }: { + query: RuleQuery; + language: Language; + filters: unknown; + index: IndexPatternArray; + exceptionFilter: Filter | undefined; + fields?: DataViewFieldBase[]; + }): Promise => { + const config: EsQueryConfig = { + allowLeadingWildcards: true, + queryStringOptions: { analyze_wildcard: true }, + ignoreFilterIfFieldNotInIndex: false, + dateFormatTZ: 'Zulu', + }; + + const initialQuery = { query, language }; + const allFilters = getAllFilters(filters as Filter[], exceptionFilter); + + const title = (index ?? []).join(); + + const dataViewLazy = await dataViewsService.createDataViewLazy({ title }); + + const flds = await queryToFields({ + dataView: dataViewLazy, + request: { query: [initialQuery], filters: allFilters }, + }); + + const dataViewLimitedFields = new DataView({ + spec: { title }, + fieldFormats: {} as unknown as FieldFormatsStartCommon, + shortDotsEnable: false, + metaFields: [], + }); + + dataViewLimitedFields.fields.replaceAll(Object.values(flds).map((fld) => fld.toSpec())); + + return buildEsQuery(dataViewLimitedFields, initialQuery, allFilters, config); + }; From 072cad1ab80827b06a20a297b6788776c3ce34e0 Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Tue, 18 Jun 2024 17:39:06 -0500 Subject: [PATCH 064/123] [Security Solution][Notes] - add feature flag, new expandable flyout tab and manage entry (#186299) --- packages/deeplinks/security/deep_links.ts | 1 + .../security_solution/common/constants.ts | 16 +------- .../common/experimental_features.ts | 5 +++ .../public/app/translations.ts | 17 ++------- .../left/components/notes_details.tsx | 18 +++++++++ .../flyout/document_details/left/index.tsx | 18 ++++++--- .../flyout/document_details/left/tabs.tsx | 14 +++++++ .../document_details/left/tabs/notes_tab.tsx | 25 ++++++++++++ .../document_details/left/tabs/test_ids.ts | 1 + .../flyout/document_details/left/test_ids.ts | 1 + .../public/management/links.ts | 20 ++++++++++ .../notes/pages/note_management_page.tsx | 18 +++++++++ .../public/timelines/routes.tsx | 38 ++++++++++++++++--- .../translations/translations/fr-FR.json | 3 -- .../translations/translations/ja-JP.json | 3 -- .../translations/translations/zh-CN.json | 3 -- 16 files changed, 153 insertions(+), 48 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/left/components/notes_details.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/notes_tab.tsx create mode 100644 x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx diff --git a/packages/deeplinks/security/deep_links.ts b/packages/deeplinks/security/deep_links.ts index ea1d818cf8010e..c127a8bfafdf2b 100644 --- a/packages/deeplinks/security/deep_links.ts +++ b/packages/deeplinks/security/deep_links.ts @@ -86,4 +86,5 @@ export enum SecurityPageName { entityAnalyticsManagement = 'entity_analytics-management', entityAnalyticsAssetClassification = 'entity_analytics-asset-classification', coverageOverview = 'coverage-overview', + notesManagement = 'notes-management', } diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 1822e6be5cb812..70fb550e798e16 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -121,20 +121,7 @@ export const ENTITY_ANALYTICS_PATH = '/entity_analytics' as const; export const ENTITY_ANALYTICS_MANAGEMENT_PATH = `/entity_analytics_management` as const; export const ENTITY_ANALYTICS_ASSET_CRITICALITY_PATH = `/entity_analytics_asset_criticality` as const; -export const APP_OVERVIEW_PATH = `${APP_PATH}${OVERVIEW_PATH}` as const; -export const APP_LANDING_PATH = `${APP_PATH}${LANDING_PATH}` as const; -export const APP_DETECTION_RESPONSE_PATH = `${APP_PATH}${DETECTION_RESPONSE_PATH}` as const; -export const APP_MANAGEMENT_PATH = `${APP_PATH}${MANAGEMENT_PATH}` as const; - export const APP_ALERTS_PATH = `${APP_PATH}${ALERTS_PATH}` as const; -export const APP_RULES_PATH = `${APP_PATH}${RULES_PATH}` as const; -export const APP_EXCEPTIONS_PATH = `${APP_PATH}${EXCEPTIONS_PATH}` as const; - -export const APP_HOSTS_PATH = `${APP_PATH}${HOSTS_PATH}` as const; -export const APP_USERS_PATH = `${APP_PATH}${USERS_PATH}` as const; -export const APP_NETWORK_PATH = `${APP_PATH}${NETWORK_PATH}` as const; -export const APP_KUBERNETES_PATH = `${APP_PATH}${KUBERNETES_PATH}` as const; -export const APP_TIMELINES_PATH = `${APP_PATH}${TIMELINES_PATH}` as const; export const APP_CASES_PATH = `${APP_PATH}${CASES_PATH}` as const; export const APP_ENDPOINTS_PATH = `${APP_PATH}${ENDPOINTS_PATH}` as const; export const APP_POLICIES_PATH = `${APP_PATH}${POLICIES_PATH}` as const; @@ -145,8 +132,7 @@ export const APP_HOST_ISOLATION_EXCEPTIONS_PATH = export const APP_BLOCKLIST_PATH = `${APP_PATH}${BLOCKLIST_PATH}` as const; export const APP_RESPONSE_ACTIONS_HISTORY_PATH = `${APP_PATH}${RESPONSE_ACTIONS_HISTORY_PATH}` as const; -export const APP_ENTITY_ANALYTICS_PATH = `${APP_PATH}${ENTITY_ANALYTICS_PATH}` as const; -export const APP_DATA_QUALITY_PATH = `${APP_PATH}${DATA_QUALITY_PATH}` as const; +export const NOTES_MANAGEMENT_PATH = `/notes_management` as const; // cloud logs to exclude from default index pattern export const EXCLUDE_ELASTIC_CLOUD_INDICES = ['-*elastic-cloud-logs-*']; diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 1a42a4dcce371b..761ec8d26035fe 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -114,6 +114,11 @@ export const allowedExperimentalValues = Object.freeze({ */ expandableFlyoutDisabled: false, + /** + * Enables new notes + */ + notesEnabled: false, + /** * Enables the Assistant Model Evaluation advanced setting and API endpoint, introduced in `8.11.0`. */ diff --git a/x-pack/plugins/security_solution/public/app/translations.ts b/x-pack/plugins/security_solution/public/app/translations.ts index 0449881d6a636a..dcadd74245f242 100644 --- a/x-pack/plugins/security_solution/public/app/translations.ts +++ b/x-pack/plugins/security_solution/public/app/translations.ts @@ -25,6 +25,10 @@ export const ENTITY_ANALYTICS_RISK_SCORE = i18n.translate( } ); +export const NOTES = i18n.translate('xpack.securitySolution.navigation.notesManagement', { + defaultMessage: 'Notes', +}); + export const ASSET_CRITICALITY = i18n.translate( 'xpack.securitySolution.navigation.assetCriticality', { @@ -143,12 +147,6 @@ export const HOST_ISOLATION_EXCEPTIONS = i18n.translate( defaultMessage: 'Host isolation exceptions', } ); -export const DETECT = i18n.translate('xpack.securitySolution.navigation.detect', { - defaultMessage: 'Detect', -}); -export const FINDINGS = i18n.translate('xpack.securitySolution.navigation.findings', { - defaultMessage: 'Findings', -}); export const EXPLORE = i18n.translate('xpack.securitySolution.navigation.explore', { defaultMessage: 'Explore', }); @@ -177,10 +175,3 @@ export const PROTECTION_UPDATES = i18n.translate( export const CREATE_NEW_RULE = i18n.translate('xpack.securitySolution.navigation.newRuleTitle', { defaultMessage: 'Create new rule', }); - -export const THREAT_INTELLIGENCE = i18n.translate( - 'xpack.securitySolution.navigation.threatIntelligence', - { - defaultMessage: 'Intelligence', - } -); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/notes_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/notes_details.tsx new file mode 100644 index 00000000000000..3c23ab55cff0f1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/notes_details.tsx @@ -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 React, { memo } from 'react'; + +/** + * List all the notes for a document id and allows to create new notes associated with that document. + * Displayed in the document details expandable flyout left section. + */ +export const NotesDetails = memo(() => { + return <>; +}); + +NotesDetails.displayName = 'NotesDetails'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx index 84e9d2553a4220..a93b1e7e7a4fbd 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx @@ -9,6 +9,7 @@ import type { FC } from 'react'; import React, { memo, useMemo } from 'react'; import type { FlyoutPanelProps, PanelPath } from '@kbn/expandable-flyout'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { DocumentDetailsLeftPanelKey } from '../shared/constants/panel_keys'; import { useKibana } from '../../../common/lib/kibana'; import { PanelHeader } from './header'; @@ -20,11 +21,12 @@ import { EventKind } from '../shared/constants/event_kinds'; import { useLeftPanelContext } from './context'; import { LeftPanelTour } from './components/tour'; -export type LeftPanelPaths = 'visualize' | 'insights' | 'investigation' | 'response'; +export type LeftPanelPaths = 'visualize' | 'insights' | 'investigation' | 'response' | 'notes'; export const LeftPanelVisualizeTab: LeftPanelPaths = 'visualize'; export const LeftPanelInsightsTab: LeftPanelPaths = 'insights'; export const LeftPanelInvestigationTab: LeftPanelPaths = 'investigation'; export const LeftPanelResponseTab: LeftPanelPaths = 'response'; +export const LeftPanelNotesTab: LeftPanelPaths = 'notes'; export interface LeftPanelProps extends FlyoutPanelProps { key: typeof DocumentDetailsLeftPanelKey; @@ -41,14 +43,18 @@ export const LeftPanel: FC> = memo(({ path }) => { const { openLeftPanel } = useExpandableFlyoutApi(); const { eventId, indexName, scopeId, getFieldsData } = useLeftPanelContext(); const eventKind = getField(getFieldsData('event.kind')); + const notesEnabled = useIsExperimentalFeatureEnabled('notesEnabled'); - const tabsDisplayed = useMemo( - () => + const tabsDisplayed = useMemo(() => { + const tabList = eventKind === EventKind.signal ? [tabs.insightsTab, tabs.investigationTab, tabs.responseTab] - : [tabs.insightsTab], - [eventKind] - ); + : [tabs.insightsTab]; + if (notesEnabled) { + tabList.push(tabs.notesTab); + } + return tabList; + }, [eventKind, notesEnabled]); const selectedTabId = useMemo(() => { const defaultTab = tabsDisplayed[0].id; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs.tsx index 4851f4a455959a..6a066ffb346485 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs.tsx @@ -8,6 +8,7 @@ import type { ReactElement } from 'react'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { NotesTab } from './tabs/notes_tab'; import { VisualizeTab } from './tabs/visualize_tab'; import { InvestigationTab } from './tabs/investigation_tab'; import { InsightsTab } from './tabs/insights_tab'; @@ -15,6 +16,7 @@ import type { LeftPanelPaths } from '.'; import { INSIGHTS_TAB_TEST_ID, INVESTIGATION_TAB_TEST_ID, + NOTES_TAB_TEST_ID, RESPONSE_TAB_TEST_ID, VISUALIZE_TAB_TEST_ID, } from './test_ids'; @@ -74,3 +76,15 @@ export const responseTab: LeftPanelTabType = { ), content: , }; + +export const notesTab: LeftPanelTabType = { + id: 'notes', + 'data-test-subj': NOTES_TAB_TEST_ID, + name: ( + + ), + content: , +}; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/notes_tab.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/notes_tab.tsx new file mode 100644 index 00000000000000..5f95fc67478aa2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/notes_tab.tsx @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo } from 'react'; +import { EuiPanel } from '@elastic/eui'; +import { NotesDetails } from '../components/notes_details'; +import { NOTES_TAB_CONTENT_TEST_ID } from './test_ids'; + +/** + * Notes view displayed in the document details expandable flyout left section + * // TODO to be implemented + */ +export const NotesTab = memo(() => { + return ( + + + + ); +}); + +NotesTab.displayName = 'NotesTab'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/test_ids.ts index 4630a19d08c985..1e99fb63d18a56 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/test_ids.ts @@ -29,3 +29,4 @@ export const INSIGHTS_TAB_CORRELATIONS_BUTTON_TEST_ID = `${INSIGHTS_TAB_TEST_ID}CorrelationsButton` as const; export const INVESTIGATION_TAB_CONTENT_TEST_ID = `${PREFIX}InvestigationsTabContent` as const; export const RESPONSE_TAB_CONTENT_TEST_ID = `${PREFIX}ResponseTabContent` as const; +export const NOTES_TAB_CONTENT_TEST_ID = `${PREFIX}NotesTabContent` as const; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/left/test_ids.ts index beb7971b3a8614..9f5eeb035786ce 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/test_ids.ts @@ -11,3 +11,4 @@ export const VISUALIZE_TAB_TEST_ID = `${PREFIX}VisualizeTab` as const; export const INSIGHTS_TAB_TEST_ID = `${PREFIX}InsightsTab` as const; export const INVESTIGATION_TAB_TEST_ID = `${PREFIX}InvestigationTab` as const; export const RESPONSE_TAB_TEST_ID = `${PREFIX}ResponseTab` as const; +export const NOTES_TAB_TEST_ID = `${PREFIX}NotesTab` as const; diff --git a/x-pack/plugins/security_solution/public/management/links.ts b/x-pack/plugins/security_solution/public/management/links.ts index 91bf4e958f6fb9..21a5fc69ca1d9e 100644 --- a/x-pack/plugins/security_solution/public/management/links.ts +++ b/x-pack/plugins/security_solution/public/management/links.ts @@ -22,6 +22,7 @@ import { EVENT_FILTERS_PATH, HOST_ISOLATION_EXCEPTIONS_PATH, MANAGE_PATH, + NOTES_MANAGEMENT_PATH, POLICIES_PATH, RESPONSE_ACTIONS_HISTORY_PATH, SecurityPageName, @@ -39,6 +40,7 @@ import { TRUSTED_APPLICATIONS, ENTITY_ANALYTICS_RISK_SCORE, ASSET_CRITICALITY, + NOTES, } from '../app/translations'; import { licenseService } from '../common/hooks/use_license'; import type { LinkItem } from '../common/links/types'; @@ -85,6 +87,12 @@ const categories = [ }), linkIds: [SecurityPageName.cloudDefendPolicies], }, + { + label: i18n.translate('xpack.securitySolution.appLinks.category.investigations', { + defaultMessage: 'Investigations', + }), + linkIds: [SecurityPageName.notesManagement], + }, ]; export const links: LinkItem = { @@ -215,6 +223,18 @@ export const links: LinkItem = { hideTimeline: true, }, cloudDefendLink, + { + id: SecurityPageName.notesManagement, + title: NOTES, + description: i18n.translate('xpack.securitySolution.appLinks.notesManagementDescription', { + defaultMessage: 'Visualize and delete notes.', + }), + landingIcon: IconTool, // TODO get new icon + path: NOTES_MANAGEMENT_PATH, + skipUrlState: true, + hideTimeline: true, + experimentalKey: 'notesEnabled', + }, ], }; diff --git a/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx b/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx new file mode 100644 index 00000000000000..1964fa65fd96fd --- /dev/null +++ b/x-pack/plugins/security_solution/public/notes/pages/note_management_page.tsx @@ -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 React from 'react'; + +/** + * Page to allow users to manage notes. The page is accessible via the Investigations section within the Manage page. + * // TODO to be implemented + */ +export const NoteManagementPage = () => { + return <>; +}; + +NoteManagementPage.displayName = 'NoteManagementPage'; diff --git a/x-pack/plugins/security_solution/public/timelines/routes.tsx b/x-pack/plugins/security_solution/public/timelines/routes.tsx index b64c80cd23036e..a7d63730071927 100644 --- a/x-pack/plugins/security_solution/public/timelines/routes.tsx +++ b/x-pack/plugins/security_solution/public/timelines/routes.tsx @@ -5,14 +5,38 @@ * 2.0. */ -import React from 'react'; +import React, { memo } from 'react'; import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; -import { Timelines } from './pages'; -import { TIMELINES_PATH } from '../../common/constants'; -import type { SecuritySubPluginRoutes } from '../app/types'; -import { SecurityPageName } from '../app/types'; +import { Switch } from 'react-router-dom'; +import { Route } from '@kbn/shared-ux-router'; +import { SpyRoute } from '../common/utils/route/spy_routes'; +import { NotFoundPage } from '../app/404'; +import { NoteManagementPage } from '../notes/pages/note_management_page'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; +import { SecurityPageName } from '../app/types'; +import type { SecuritySubPluginRoutes } from '../app/types'; +import { NOTES_MANAGEMENT_PATH, TIMELINES_PATH } from '../../common/constants'; +import { Timelines } from './pages'; + +const NoteManagementTelemetry = () => ( + + + + + + +); + +const NoteManagementContainer = memo(() => { + return ( + + + + + ); +}); +NoteManagementContainer.displayName = 'NoteManagementContainer'; const TimelinesRoutes = () => ( @@ -27,4 +51,8 @@ export const routes: SecuritySubPluginRoutes = [ path: TIMELINES_PATH, component: TimelinesRoutes, }, + { + path: NOTES_MANAGEMENT_PATH, + component: NoteManagementContainer, + }, ]; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index cf8a0222a03780..d8143a8c98bf34 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -36624,7 +36624,6 @@ "xpack.securitySolution.navigation.case": "Cas", "xpack.securitySolution.navigation.coverageOverviewDashboard": "Couverture MITRE ATT&CK®", "xpack.securitySolution.navigation.dashboards": "Tableaux de bord", - "xpack.securitySolution.navigation.detect": "Détecter", "xpack.securitySolution.navigation.detectionResponse": "Détection et réponse", "xpack.securitySolution.navigation.detectionRules": "Règles de détection (SIEM)", "xpack.securitySolution.navigation.ecsDataQualityDashboard": "Qualité des données", @@ -36632,7 +36631,6 @@ "xpack.securitySolution.navigation.entityRiskScore": "Score de risque des entités", "xpack.securitySolution.navigation.exceptions": "Listes d'exceptions partagées", "xpack.securitySolution.navigation.explore": "Explorer", - "xpack.securitySolution.navigation.findings": "Résultats", "xpack.securitySolution.navigation.gettingStarted": "Démarrer", "xpack.securitySolution.navigation.hosts": "Hôtes", "xpack.securitySolution.navigation.kubernetes": "Kubernetes", @@ -36644,7 +36642,6 @@ "xpack.securitySolution.navigation.protectionUpdates": "Mises à jour de la protection", "xpack.securitySolution.navigation.responseActionsHistory": "Historique des actions de réponse", "xpack.securitySolution.navigation.rules": "Règles", - "xpack.securitySolution.navigation.threatIntelligence": "Intelligence", "xpack.securitySolution.navigation.timelines": "Chronologies", "xpack.securitySolution.navigation.users": "Utilisateurs", "xpack.securitySolution.network.ipDetails.ipOverview.asDestinationDropDownOptionLabel": "Comme destination", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index c50d9b9b36b2f1..f5b22bce86c92f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -36599,7 +36599,6 @@ "xpack.securitySolution.navigation.case": "ケース", "xpack.securitySolution.navigation.coverageOverviewDashboard": "MITRE ATT&CK®の範囲", "xpack.securitySolution.navigation.dashboards": "ダッシュボード", - "xpack.securitySolution.navigation.detect": "検知", "xpack.securitySolution.navigation.detectionResponse": "検出と対応", "xpack.securitySolution.navigation.detectionRules": "検出ルール(SIEM)", "xpack.securitySolution.navigation.ecsDataQualityDashboard": "データ品質", @@ -36607,7 +36606,6 @@ "xpack.securitySolution.navigation.entityRiskScore": "エンティティリスクスコア", "xpack.securitySolution.navigation.exceptions": "共有例外リスト", "xpack.securitySolution.navigation.explore": "探索", - "xpack.securitySolution.navigation.findings": "調査結果", "xpack.securitySolution.navigation.gettingStarted": "使ってみる", "xpack.securitySolution.navigation.hosts": "ホスト", "xpack.securitySolution.navigation.kubernetes": "Kubernetes", @@ -36619,7 +36617,6 @@ "xpack.securitySolution.navigation.protectionUpdates": "保護更新", "xpack.securitySolution.navigation.responseActionsHistory": "対応アクション履歴", "xpack.securitySolution.navigation.rules": "ルール", - "xpack.securitySolution.navigation.threatIntelligence": "インテリジェンス", "xpack.securitySolution.navigation.timelines": "タイムライン", "xpack.securitySolution.navigation.users": "ユーザー", "xpack.securitySolution.network.ipDetails.ipOverview.asDestinationDropDownOptionLabel": "送信先として", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index cbfe1c3c90544c..d94eb2aed9eb78 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -36642,7 +36642,6 @@ "xpack.securitySolution.navigation.case": "案例", "xpack.securitySolution.navigation.coverageOverviewDashboard": "MITRE ATT&CK® 支持", "xpack.securitySolution.navigation.dashboards": "仪表板", - "xpack.securitySolution.navigation.detect": "检测", "xpack.securitySolution.navigation.detectionResponse": "检测和响应", "xpack.securitySolution.navigation.detectionRules": "检测规则 (SIEM)", "xpack.securitySolution.navigation.ecsDataQualityDashboard": "数据质量", @@ -36650,7 +36649,6 @@ "xpack.securitySolution.navigation.entityRiskScore": "实体风险分数", "xpack.securitySolution.navigation.exceptions": "共享例外列表", "xpack.securitySolution.navigation.explore": "浏览", - "xpack.securitySolution.navigation.findings": "结果", "xpack.securitySolution.navigation.gettingStarted": "开始使用", "xpack.securitySolution.navigation.hosts": "主机", "xpack.securitySolution.navigation.kubernetes": "Kubernetes", @@ -36662,7 +36660,6 @@ "xpack.securitySolution.navigation.protectionUpdates": "防护更新", "xpack.securitySolution.navigation.responseActionsHistory": "响应操作历史记录", "xpack.securitySolution.navigation.rules": "规则", - "xpack.securitySolution.navigation.threatIntelligence": "情报", "xpack.securitySolution.navigation.timelines": "时间线", "xpack.securitySolution.navigation.users": "用户", "xpack.securitySolution.network.ipDetails.ipOverview.asDestinationDropDownOptionLabel": "作为目标", From fc6838c6ceaf2dbf029b7871cf7d51d91e86dfcc Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 19 Jun 2024 01:38:55 +0100 Subject: [PATCH 065/123] skip flaky suite (#186387) --- .../pages/cis_integrations/kspm/cis_integration_eks.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts index 3d115fd33f8bf0..22b661dbbdc68c 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts @@ -108,7 +108,8 @@ export default function (providerContext: FtrProviderContext) { }); }); - describe('KSPM EKS Shared Credentials', () => { + // FLAKY: https://github.com/elastic/kibana/issues/186387 + describe.skip('KSPM EKS Shared Credentials', () => { it('KSPM EKS Shared Credentials Workflow', async () => { const sharedCredentialFile = 'sharedCredentialFileTest'; const sharedCredentialProfileName = 'sharedCredentialProfileNameTest'; From fe07ada72a1b320bf93b8e260cefa4242b2c04d8 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 19 Jun 2024 01:40:20 +0100 Subject: [PATCH 066/123] skip flaky suite (#186302) --- .../pages/cis_integrations/cnvm/cis_integration_cnvm.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts index 1e5ff7868f9029..1b57e9a65d41e9 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts @@ -23,7 +23,8 @@ export default function (providerContext: FtrProviderContext) { await cisIntegration.navigateToAddIntegrationCspmPage(); }); - describe('CNVM AWS', () => { + // FLAKY: https://github.com/elastic/kibana/issues/186302 + describe.skip('CNVM AWS', () => { it('Hyperlink on PostInstallation Modal should have the correct URL', async () => { await cisIntegration.navigateToAddIntegrationCnvmPage(); await cisIntegration.clickSaveButton(); From d2809ada066e4868406f9b14bc326b3ea82ded87 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 19 Jun 2024 01:45:18 +0100 Subject: [PATCH 067/123] skip flaky suite (#186389) --- .../pages/cis_integrations/kspm/cis_integration_eks.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts index 22b661dbbdc68c..cd63bc117224d9 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/kspm/cis_integration_eks.ts @@ -75,7 +75,8 @@ export default function (providerContext: FtrProviderContext) { }); }); - describe('KSPM EKS Temporary Keys', () => { + // FLAKY: https://github.com/elastic/kibana/issues/186389 + describe.skip('KSPM EKS Temporary Keys', () => { it('KSPM EKS Temporary Keys Workflow', async () => { const accessKeyId = 'accessKeyIdTest'; const accessKeySecretKey = 'accessKeySecretKeyTest'; From 404e8c9374e9b9f5a9bae490d43db2eed65f1c1d Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 19 Jun 2024 01:47:42 +0100 Subject: [PATCH 068/123] skip flaky suite (#185216) --- .../test_suites/common/index_management/inference_endpoints.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/inference_endpoints.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/inference_endpoints.ts index cacf294b4c81af..87b760d84540c8 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/index_management/inference_endpoints.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/inference_endpoints.ts @@ -18,7 +18,8 @@ export default function ({ getService }: FtrProviderContext) { const taskType = 'sparse_embedding'; const service = 'elser'; - describe('Inference endpoints', function () { + // FLAKY: https://github.com/elastic/kibana/issues/185216 + describe.skip('Inference endpoints', function () { // test adds new trained model '.elser_model_2_linux-x86_64', but does not clean it. Follow up tests are affected this.tags(['failsOnMKI']); before(async () => { From f74ada83958d1c5682b3fdf0b319b64520007f2b Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 19 Jun 2024 01:49:18 +0100 Subject: [PATCH 069/123] skip flaky suite (#186416) --- test/functional/apps/discover/esql/_esql_columns.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/functional/apps/discover/esql/_esql_columns.ts b/test/functional/apps/discover/esql/_esql_columns.ts index ba7f8447529abc..d48ec83f6ba910 100644 --- a/test/functional/apps/discover/esql/_esql_columns.ts +++ b/test/functional/apps/discover/esql/_esql_columns.ts @@ -36,7 +36,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { defaultIndex: 'logstash-*', }; - describe('discover esql columns', async function () { + // FLAKY: https://github.com/elastic/kibana/issues/186416 + describe.skip('discover esql columns', async function () { before(async () => { await kibanaServer.savedObjects.cleanStandardList(); await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); From 2d6484d0f4b43d99473221c0c627a76ac3a078e8 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 19 Jun 2024 01:51:11 +0100 Subject: [PATCH 070/123] skip flaky suite (#157642) --- .../apps/cases/group2/attachment_framework.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts b/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts index 876e4d21230197..8c4dd47532255e 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/group2/attachment_framework.ts @@ -263,7 +263,8 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { }); }); - describe('Modal', () => { + // FLAKY: https://github.com/elastic/kibana/issues/157642 + describe.skip('Modal', () => { const createdCases = new Map(); const openModal = async () => { From 2194f85314b7c46d6614bbd177dddb37e8ac2e9c Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 19 Jun 2024 01:52:35 +0100 Subject: [PATCH 071/123] skip flaky suite (#184681) --- .../apis/integrations/inputs_with_standalone_docker_agent.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts b/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts index ca1d8c0c3f312c..64a9077b916d98 100644 --- a/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts +++ b/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts @@ -25,7 +25,8 @@ export default function (providerContext: FtrProviderContext) { const config = getService('config'); const log = getService('log'); - describe('inputs_with_standalone_docker_agent', () => { + // FLAKY: https://github.com/elastic/kibana/issues/184681 + describe.skip('inputs_with_standalone_docker_agent', () => { skipIfNoDockerRegistry(providerContext); let apiKey: string; let agent: AgentProcess; From 1c7b5952b31cea4ed68ba2df5ad34ba043bd8852 Mon Sep 17 00:00:00 2001 From: Ryan Keairns Date: Tue, 18 Jun 2024 18:27:39 -0700 Subject: [PATCH 072/123] [ES|QL] Theme updates for text based languages editor (#186345) ## Summary This is a design pass at the editor. Functionality and layout have not been changed. ### What has changed? - Color settings in the `esql_theme.ts` - Added additional rule groups for color treatment (e.g. more operators and values) - Replaced hardcoded style values with EUI variables - As a result, one set of theme colors now works across light and dark mode - Made a few small Monaco configuration (i.e. options) changes that affect the UI/visual output (e.g. active line styles, line height, font... the font size is the same, but I believe these other changes will make it feel larger/more readable) - Re-ordered the options set to more easily find what is/is not enabled - Shortened the height of the top bar; tightened up the padding; more closely matches the footer design ### How does it look? *Light mode* ![CleanShot 2024-06-17 at 16 13 46@2x](https://github.com/elastic/kibana/assets/446285/5e78c2ac-5be8-4138-b1bf-616373c98bf1) *Dark mode* ![CleanShot 2024-06-17 at 16 15 49@2x](https://github.com/elastic/kibana/assets/446285/f739742e-92d8-46d0-a4d2-26f8f2669044) *Compact* ![CleanShot 2024-06-17 at 16 15 26@2x](https://github.com/elastic/kibana/assets/446285/a0f2b129-5973-4742-b428-16ef4f8b1eca) ### What about the other things we saw in the Slack screenshots... I have some other ideas cookin', but I would like to iterate on those concepts in Figma and get additional feedback. These entail the edge-to-edge design, less borders, consolidated header and footer, smaller CTA buttons, full-height field list, etc. Something like this...

Additional design considerations not in this PR ![CleanShot 2024-06-14 at 22 38 34@2x](https://github.com/elastic/kibana/assets/446285/dd5e0f12-1c9a-4ade-ad80-22376f841a41)
### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../kbn-monaco/src/esql/lib/esql_theme.ts | 70 ++++++++++++++----- .../src/editor_footer.tsx | 6 -- .../kbn-text-based-editor/src/overwrite.scss | 66 ++++++++++------- .../src/query_history.tsx | 2 + .../src/text_based_languages_editor.styles.ts | 6 +- .../src/text_based_languages_editor.tsx | 56 ++++++++------- .../query_string_input/query_bar_top_row.tsx | 4 +- 7 files changed, 130 insertions(+), 80 deletions(-) diff --git a/packages/kbn-monaco/src/esql/lib/esql_theme.ts b/packages/kbn-monaco/src/esql/lib/esql_theme.ts index f9ed8c6849acc4..c88a8fc02b26df 100644 --- a/packages/kbn-monaco/src/esql/lib/esql_theme.ts +++ b/packages/kbn-monaco/src/esql/lib/esql_theme.ts @@ -12,15 +12,6 @@ import { ESQL_TOKEN_POSTFIX } from './constants'; import { monaco } from '../../monaco_imports'; const buildRuleGroup = themeRuleGroupBuilderFactory(ESQL_TOKEN_POSTFIX); -const COMMANDS_COLORS = { - dark: '#a68ac5', - light: '#765b96', -}; - -const FUNCTIONS_COLORS = { - dark: '#d97797', - light: '#a34a68', -}; export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({ base: darkMode ? 'vs-dark' : 'vs', @@ -55,10 +46,16 @@ export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({ euiThemeVars.euiTextColor ), + // source commands + ...buildRuleGroup( + ['from', 'row', 'show', 'meta'], + euiThemeVars.euiColorPrimaryText, + true // isBold + ), + // commands ...buildRuleGroup( [ - 'from', 'metrics', 'metadata', 'mv_expand', @@ -80,9 +77,6 @@ export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({ 'in', 'as', 'expr_ws', - 'row', - 'show', - 'meta', 'limit', 'nulls_ordering_direction', 'nulls_ordering', @@ -90,17 +84,37 @@ export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({ 'enrich', 'on', 'with', + 'asc', + 'desc', ], - darkMode ? COMMANDS_COLORS.dark : COMMANDS_COLORS.light + euiThemeVars.euiColorAccentText, + true // isBold ), // functions - ...buildRuleGroup(['functions'], darkMode ? FUNCTIONS_COLORS.dark : FUNCTIONS_COLORS.light), + ...buildRuleGroup(['functions'], euiThemeVars.euiColorPrimaryText), // operators ...buildRuleGroup( - ['or', 'and', 'rp', 'lp', 'plus', 'minus', 'asterisk', 'slash'], - euiThemeVars.euiTextSubduedColor + [ + 'or', + 'and', + 'rp', // ')' + 'lp', // '(' + 'eq', // '==' + 'cieq', // '=~' + 'neq', // '!=' + 'lt', // '<' + 'lte', // '<=' + 'gt', // '>' + 'gte', // '>=' + 'plus', // '+' + 'minus', // '-' + 'asterisk', // '*' + 'slash', // '/' + 'percent', // '%' + ], + euiThemeVars.euiColorPrimaryText ), // comments @@ -113,8 +127,26 @@ export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({ 'src_line_comment', 'src_multiline_comment', ], - darkMode ? euiThemeVars.euiColorDarkestShade : euiThemeVars.euiColorMediumShade + euiThemeVars.euiColorDisabledText + ), + + // values + ...buildRuleGroup( + ['quoted_string', 'integer_literal', 'decimal_literal'], + euiThemeVars.euiColorSuccessText ), ], - colors: {}, + colors: { + 'editor.foreground': euiThemeVars.euiTextColor, + 'editor.background': euiThemeVars.euiColorEmptyShade, + 'editor.lineHighlightBackground': euiThemeVars.euiColorLightestShade, + 'editor.lineHighlightBorder': euiThemeVars.euiColorLightestShade, + 'editor.selectionHighlightBackground': euiThemeVars.euiColorLightestShade, + 'editor.selectionHighlightBorder': euiThemeVars.euiColorLightShade, + 'editorSuggestWidget.background': euiThemeVars.euiColorEmptyShade, + 'editorSuggestWidget.border': euiThemeVars.euiColorEmptyShade, + 'editorSuggestWidget.foreground': euiThemeVars.euiTextColor, + 'editorSuggestWidget.selectedBackground': euiThemeVars.euiColorPrimary, + 'editorSuggestWidget.selectedForeground': euiThemeVars.euiColorEmptyShade, + }, }); diff --git a/packages/kbn-text-based-editor/src/editor_footer.tsx b/packages/kbn-text-based-editor/src/editor_footer.tsx index 697563ebc404cb..27a6ffbeabbdbe 100644 --- a/packages/kbn-text-based-editor/src/editor_footer.tsx +++ b/packages/kbn-text-based-editor/src/editor_footer.tsx @@ -145,7 +145,6 @@ export const EditorFooter = memo(function EditorFooter({ queryHasChanged, measuredContainerWidth, }: EditorFooterProps) { - const { euiTheme } = useEuiTheme(); const [isErrorPopoverOpen, setIsErrorPopoverOpen] = useState(false); const [isWarningPopoverOpen, setIsWarningPopoverOpen] = useState(false); const onUpdateAndSubmit = useCallback( @@ -162,10 +161,6 @@ export const EditorFooter = memo(function EditorFooter({ [runQuery, updateQuery] ); - const shadowStyle = isInCompactMode - ? `inset 0 0px 0, inset 0 -1px 0 ${euiTheme.border.color}` - : 'none'; - return ( diff --git a/packages/kbn-text-based-editor/src/overwrite.scss b/packages/kbn-text-based-editor/src/overwrite.scss index e24fd604d7268f..7c66fe96e36cb4 100644 --- a/packages/kbn-text-based-editor/src/overwrite.scss +++ b/packages/kbn-text-based-editor/src/overwrite.scss @@ -1,45 +1,63 @@ -.TextBasedLangEditor .monaco-editor { - border-top-left-radius: 6px; - border-bottom-left-radius: 6px; +/* Editor styles for any layout mode */ +/* NOTE: Much of this is overriding Monaco styles so the specificity is intentional */ + +// Radius for both the main container and the margin (container for line numbers) +.TextBasedLangEditor .monaco-editor, .TextBasedLangEditor .monaco-editor .margin, .TextBasedLangEditor .monaco-editor .overflow-guard { + border-top-left-radius: $euiBorderRadius; + border-bottom-left-radius: $euiBorderRadius; } .TextBasedLangEditor .monaco-editor .monaco-hover { display: none !important; } -.TextBasedLangEditor--expanded .monaco-editor .monaco-hover { - display: block !important; +.TextBasedLangEditor .monaco-editor .margin-view-overlays .line-numbers { + color: $euiColorDisabledText; } -.TextBasedLangEditor .monaco-editor .margin { - border-top-left-radius: 6px; - border-bottom-left-radius: 6px; +// Currently focused line(s) +.TextBasedLangEditor .monaco-editor .current-line ~ .line-numbers { + color: $euiTextSubduedColor; } -.TextBasedLangEditor--compact .monaco-editor { - border-top-left-radius: 0; - border-bottom-left-radius: 0; +// Suggest (autocomplete) menu +.TextBasedLangEditor .monaco-editor .suggest-widget, .TextBasedLangEditor .monaco-editor .suggest-details-container { + @include euiBottomShadow; + border-radius: $euiBorderRadius; } -.TextBasedLangEditor--compact .monaco-editor .margin { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - background-color: $euiColorLightestShade; - color: $euiColorDisabledText; +.TextBasedLangEditor .monaco-editor .suggest-details-container { + background-color: $euiColorEmptyShade; + line-height: 1.5rem; } -.TextBasedLangEditor .monaco-editor .margin-view-overlays .line-numbers { - color: $euiColorDisabledText; +.TextBasedLangEditor_errorMessage { + @include euiTextBreakWord; } -.TextBasedLangEditor .monaco-editor .current-line ~ .line-numbers { - color: $euiTextSubduedColor; -} +/* For compact mode */ +// All scrollable containers (e.g. main container and suggest menu) .TextBasedLangEditor--compact .monaco-editor .monaco-scrollable-element { - margin-left: 4px; + margin-left: $euiSizeS; } -.TextBasedLangEditor_errorMessage { - @include euiTextBreakWord; +// Suggest menu in compact mode +.TextBasedLangEditor--compact .monaco-editor .monaco-list .monaco-scrollable-element { + margin-left: 0; + + .monaco-list-row.focused { + border-radius: $euiBorderRadius; + } } + +/* For expanded mode */ + +.TextBasedLangEditor--expanded .monaco-editor .monaco-hover { + display: block !important; +} + +.TextBasedLangEditor--expanded .monaco-editor, .TextBasedLangEditor--expanded .monaco-editor .margin, .TextBasedLangEditor--expanded .monaco-editor .overflow-guard { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} \ No newline at end of file diff --git a/packages/kbn-text-based-editor/src/query_history.tsx b/packages/kbn-text-based-editor/src/query_history.tsx index d7272e8d59e12d..9f0f82deb3db7f 100644 --- a/packages/kbn-text-based-editor/src/query_history.tsx +++ b/packages/kbn-text-based-editor/src/query_history.tsx @@ -364,6 +364,8 @@ export function QueryHistory({ .euiTable th[data-test-subj='tableHeaderCell_duration_3'] span { justify-content: flex-end; } + border-bottom-left-radius: ${euiTheme.border.radius.medium}; + border-top-left-radius: ${euiTheme.border.radius.medium}; max-height: ${isInCompactMode ? CONTAINER_MAX_HEIGHT_COMPACT : CONTAINER_MAX_HEIGHT_EXPANDED}px; overflow-y: auto; ${scrollBarStyles} diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts b/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts index 39a02a35516ab6..130d0ca69fc4a9 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts @@ -102,7 +102,7 @@ export const textBasedLanguageEditorStyles = ( }, historyContainer: { border: euiTheme.border.thin, - borderTop: `2px solid ${euiTheme.colors.lightShade}`, + borderTop: 'none', borderLeft: editorIsInline ? 'none' : euiTheme.border.thin, borderRight: editorIsInline ? 'none' : euiTheme.border.thin, backgroundColor: euiTheme.colors.lightestShade, @@ -119,8 +119,8 @@ export const textBasedLanguageEditorStyles = ( borderTopLeftRadius: editorIsInline ? 0 : euiTheme.border.radius.medium, borderTopRightRadius: editorIsInline ? 0 : euiTheme.border.radius.medium, backgroundColor: euiTheme.colors.lightestShade, - paddingLeft: euiTheme.size.xs, - paddingRight: euiTheme.size.xs, + paddingLeft: euiTheme.size.s, + paddingRight: euiTheme.size.s, paddingTop: showHeader ? euiTheme.size.s : euiTheme.size.xs, paddingBottom: showHeader ? euiTheme.size.s : euiTheme.size.xs, width: '100%', diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index b3729118f6e99d..b33d8125bfd251 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -667,41 +667,43 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ }, [language, documentationSections]); const codeEditorOptions: CodeEditorProps['options'] = { - automaticLayout: true, accessibilitySupport: 'off', + autoIndent: 'none', + automaticLayout: true, + fixedOverflowWidgets: true, folding: false, fontSize: 14, - padding: { - top: 8, - bottom: 8, - }, - scrollBeyondLastLine: false, - quickSuggestions: true, - minimap: { enabled: false }, - wordWrap: 'on', - lineNumbers: showLineNumbers ? 'on' : 'off', - theme: language === 'esql' ? ESQL_THEME_ID : isDark ? 'vs-dark' : 'vs', - lineDecorationsWidth: 12, - autoIndent: 'none', - wrappingIndent: 'none', - lineNumbersMinChars: 3, - overviewRulerLanes: 0, hideCursorInOverviewRuler: true, - scrollbar: { - horizontal: 'hidden', - vertical: 'auto', - }, - overviewRulerBorder: false, // this becomes confusing with multiple markers, so quick fixes // will be proposed only within the tooltip lightbulb: { enabled: false, }, - fixedOverflowWidgets: true, + lineDecorationsWidth: 12, + lineNumbers: showLineNumbers ? 'on' : 'off', + lineNumbersMinChars: 3, + minimap: { enabled: false }, + overviewRulerLanes: 0, + overviewRulerBorder: false, + padding: { + top: 8, + bottom: 8, + }, + quickSuggestions: true, readOnly: isLoading || isDisabled || Boolean(!isCompactFocused && codeOneLiner && codeOneLiner.includes('...')), + renderLineHighlight: !isCodeEditorExpanded ? 'none' : 'line', + renderLineHighlightOnlyWhenFocus: true, + scrollbar: { + horizontal: 'hidden', + vertical: 'auto', + }, + scrollBeyondLastLine: false, + theme: language === 'esql' ? ESQL_THEME_ID : isDark ? 'vs-dark' : 'vs', + wordWrap: 'on', + wrappingIndent: 'none', }; if (isCompactFocused) { @@ -743,7 +745,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ {!Boolean(hideMinimizeButton) && ( - + { expandCodeEditor(false); updateLinesFromModel = false; @@ -1015,6 +1017,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ borderRadius: 0, backgroundColor: isDark ? euiTheme.colors.lightestShade : '#e9edf3', border: '1px solid rgb(17 43 134 / 10%) !important', + transform: 'none !important', }, }} /> @@ -1044,6 +1047,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ backgroundColor: isDark ? euiTheme.colors.lightestShade : '#e9edf3', border: '1px solid rgb(17 43 134 / 10%) !important', borderLeft: 'transparent !important', + transform: 'none !important', }} /> diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx index 892144d07fb06c..941040dfd30f88 100644 --- a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx @@ -566,7 +566,7 @@ export const QueryBarTopRow = React.memo( : strings.getRefreshQueryLabel(); const buttonLabelRun = textBasedRunShortcut; - const iconDirty = Boolean(isQueryLangSelected) ? 'play' : 'kqlFunction'; + const iconDirty = Boolean(isQueryLangSelected) ? 'playFilled' : 'kqlFunction'; const tooltipDirty = Boolean(isQueryLangSelected) ? buttonLabelRun : buttonLabelUpdate; const isDirtyButtonLabel = Boolean(isQueryLangSelected) @@ -588,7 +588,7 @@ export const QueryBarTopRow = React.memo( onClick={onClickSubmitButton} size={shouldShowDatePickerAsBadge() ? 's' : 'm'} color={props.isDirty ? 'success' : 'primary'} - fill={props.isDirty} + fill={false} needsUpdate={props.isDirty} data-test-subj="querySubmitButton" toolTipProps={{ From 1b872fbf9dc90d3c82a569a9faef9e360fc41171 Mon Sep 17 00:00:00 2001 From: Garrett Spong Date: Tue, 18 Jun 2024 19:48:07 -0600 Subject: [PATCH 073/123] [Security Assistant] Adds client hooks and internal routes for managing Knowledge Base Entries (#184974) ## Summary This PR adds client hooks and basic REST API's for accessing and mutating Knowledge Base Entries. This is in support of @angorayc building out the new Knowledge Base settings interface. Change set includes: - [X] Refactors existing KB client hooks from `x-pack/packages/kbn-elastic-assistant/impl/knowledge_base` to be co-located next to the API methods where we put all our other hooks: `x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base` - [X] Refactors existing KB API calls and associated tests out of `kbn-elastic-assistant/impl/assistant/api/index.tsx` and into `x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/api.tsx` - [X] Adds new `find_knowledge_base_entries_route.schema.yaml` OAS for the supporting `/internal/elastic_assistant/knowledge_base/entries/_find` route - [X] Refactors `SortOrder` out of existing OAS's into the shared `schemas/common_attributes.schema.yaml` ### Client Hooks & Routes Adds new `useKnowledgeBaseEntries()` hook and corresponding `/knowledge_base/entries/_find` route for returning paginated KB Entries to populate the KB table in settings. E.g. ``` ts const { assistantFeatures: { assistantKnowledgeBaseByDefault: enableKnowledgeBaseByDefault }, http, toasts, } = useAssistantContext(); const { data: kbEntries, isLoading: isLoadingEntries } = useKnowledgeBaseEntries({ http }); ``` ###### Sample Response ``` json { "perPage": 20, "page": 1, "total": 145, "data": [ { "timestamp": "2024-06-05T21:19:56.482Z", "id": "CtBF6o8BSQy1Bdxt2FHz", "createdAt": "2024-06-05T21:19:56.482Z", "createdBy": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", "updatedAt": "2024-06-05T21:19:56.482Z", "updatedBy": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", "users": [ { "id": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", "name": "elastic" } ], "metadata": { "kbResource": "security_labs", "source": "/Users/garrettspong/dev/kibana-main/x-pack/plugins/elastic_assistant/server/knowledge_base/security_labs/2022_elastic_global_threat_report_announcement.mdx", "required": false }, "namespace": "default", "text": "[Source Content Here]", "vector": { "modelId": ".elser_model_2", "tokens": { "2": 0.06595266, ... } } }, ... ] } ``` Response is the full newly created `entry`. Same format for the entry as above in the `_find` API, and the `KnowledgeBaseEntries` cache is invalidated. Adds new `useCreateKnowledgeBaseEntry()` hook and corresponding `/knowledge_base/entries` route for creating new KB Entries ``` ts const entry: KnowledgeBaseEntryCreateProps = { metadata: { kbResource: 'user', required: true, source: 'user', }, text: 'Useful information about the user', }; const { mutate: createEntry, isLoading: isCreatingEntry } = useCreateKnowledgeBaseEntry({ http, }); await createEntry(entry); ``` Adds new `useDeleteKnowledgeBaseEntries()` hook and corresponding `/knowledge_base/entries/_bulk_action` route for deleting existing KB Entries. I left a TODO to plumb through `delete_by_query` so we can add a filter bar to the table. Need to confirm if we can do pagination with similarity search as well. ``` ts const { mutate: deleteEntries, isLoading: isDeletingEntries } = useDeleteKnowledgeBaseEntries({ http, }); await deleteEntries({ ids: ['YOE_CZABSQy1BdxtAGbs'] }) ``` See `KnowledgeBaseEntryBulkCrudActionResponse` for response formats. `KnowledgeBaseEntries` cache is invalidated upon delete. ### Checklist Delete any items that are not applicable to this PR. - [ ] ~Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)~ - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials * Feature currently behind feature flag. Documentation to be added before flag is removed. Tracked in https://github.com/elastic/security-docs/issues/5337 - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] API tests will need to be rounded out as we finalize functionality behind the feature flag --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../kbn-elastic-assistant-common/constants.ts | 5 +- .../impl/capabilities/index.ts | 5 + .../find_anonymization_fields_route.gen.ts | 6 +- ...ind_anonymization_fields_route.schema.yaml | 8 +- .../impl/schemas/common_attributes.gen.ts | 5 + .../schemas/common_attributes.schema.yaml | 6 + .../find_conversations_route.gen.ts | 6 +- .../find_conversations_route.schema.yaml | 10 +- .../impl/schemas/index.ts | 1 + .../common_attributes.schema.yaml | 1 - .../find_knowledge_base_entries_route.gen.ts | 69 +++++ ...d_knowledge_base_entries_route.schema.yaml | 102 ++++++++ .../schemas/prompts/find_prompts_route.gen.ts | 6 +- .../prompts/find_prompts_route.schema.yaml | 8 +- .../impl/assistant/api/index.test.tsx | 83 +------ .../impl/assistant/api/index.tsx | 110 +------- .../assistant/api/knowledge_base/api.test.tsx | 97 ++++++++ .../impl/assistant/api/knowledge_base/api.tsx | 114 +++++++++ .../use_create_knowledge_base_entry.tsx | 83 +++++++ .../use_delete_knowledge_base_entries.tsx | 90 +++++++ .../entries/use_knowledge_base_entries.ts | 80 ++++++ .../use_delete_knowledge_base.test.tsx | 6 +- .../use_delete_knowledge_base.tsx | 2 +- .../use_knowledge_base_status.test.tsx | 6 +- .../use_knowledge_base_status.tsx | 2 +- .../use_setup_knowledge_base.test.tsx | 6 +- .../use_setup_knowledge_base.tsx | 2 +- .../install_knowledge_base_button.tsx | 4 +- .../knowledge_base_settings.test.tsx | 8 +- .../knowledge_base_settings.tsx | 6 +- .../elastic_assistant/common/constants.ts | 3 + .../knowledge_base/index.ts | 8 +- .../langchain/content_loaders/esql_loader.ts | 8 +- .../elasticsearch_store.test.ts | 7 +- .../elasticsearch_store.ts | 5 +- .../server/routes/helpers.ts | 72 +++++- .../entries/bulk_actions_route.ts | 235 ++++++++++++++++++ .../knowledge_base/entries/create_route.ts | 55 ++-- .../knowledge_base/entries/find_route.ts | 103 ++++++++ .../server/routes/register_routes.ts | 10 +- 40 files changed, 1158 insertions(+), 285 deletions(-) create mode 100644 x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts create mode 100644 x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.schema.yaml create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/api.test.tsx create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/api.tsx create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_create_knowledge_base_entry.tsx create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_delete_knowledge_base_entries.tsx create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_knowledge_base_entries.ts rename x-pack/packages/kbn-elastic-assistant/impl/{ => assistant/api}/knowledge_base/use_delete_knowledge_base.test.tsx (94%) rename x-pack/packages/kbn-elastic-assistant/impl/{ => assistant/api}/knowledge_base/use_delete_knowledge_base.tsx (97%) rename x-pack/packages/kbn-elastic-assistant/impl/{ => assistant/api}/knowledge_base/use_knowledge_base_status.test.tsx (96%) rename x-pack/packages/kbn-elastic-assistant/impl/{ => assistant/api}/knowledge_base/use_knowledge_base_status.tsx (97%) rename x-pack/packages/kbn-elastic-assistant/impl/{ => assistant/api}/knowledge_base/use_setup_knowledge_base.test.tsx (94%) rename x-pack/packages/kbn-elastic-assistant/impl/{ => assistant/api}/knowledge_base/use_setup_knowledge_base.tsx (97%) create mode 100644 x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts create mode 100644 x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts diff --git a/x-pack/packages/kbn-elastic-assistant-common/constants.ts b/x-pack/packages/kbn-elastic-assistant-common/constants.ts index f30cb053d4ce18..74da6ab2476e28 100755 --- a/x-pack/packages/kbn-elastic-assistant-common/constants.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/constants.ts @@ -27,5 +27,6 @@ export const ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_FIND = `${ELASTIC_AI_ // TODO: Update existing 'status' endpoint to take resource as query param as to not conflict with 'entries' export const ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL = `${ELASTIC_AI_ASSISTANT_INTERNAL_URL}/knowledge_base/{resource?}`; -export const ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL = `${ELASTIC_AI_ASSISTANT_URL}/knowledge_base/entries`; -export const ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION = `${ELASTIC_AI_ASSISTANT_URL}/knowledge_base/_bulk_action`; +export const ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL = `${ELASTIC_AI_ASSISTANT_INTERNAL_URL}/knowledge_base/entries`; +export const ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_FIND = `${ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL}/_find`; +export const ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION = `${ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL}/_bulk_action`; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts index 9c734cc4b3c133..c1c101fd74cd85 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts @@ -10,6 +10,11 @@ */ export type AssistantFeatures = { [K in keyof typeof defaultAssistantFeatures]: boolean }; +/** + * Type for keys of the assistant features + */ +export type AssistantFeatureKey = keyof AssistantFeatures; + /** * Default features available to the elastic assistant */ diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen.ts index b51ea841706431..486df4547b4296 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen.ts @@ -17,6 +17,7 @@ import { z } from 'zod'; import { ArrayFromString } from '@kbn/zod-helpers'; +import { SortOrder } from '../common_attributes.gen'; import { AnonymizationFieldResponse } from './bulk_crud_anonymization_fields_route.gen'; export type FindAnonymizationFieldsSortField = z.infer; @@ -30,11 +31,6 @@ export const FindAnonymizationFieldsSortField = z.enum([ export type FindAnonymizationFieldsSortFieldEnum = typeof FindAnonymizationFieldsSortField.enum; export const FindAnonymizationFieldsSortFieldEnum = FindAnonymizationFieldsSortField.enum; -export type SortOrder = z.infer; -export const SortOrder = z.enum(['asc', 'desc']); -export type SortOrderEnum = typeof SortOrder.enum; -export const SortOrderEnum = SortOrder.enum; - export type FindAnonymizationFieldsRequestQuery = z.infer< typeof FindAnonymizationFieldsRequestQuery >; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.schema.yaml index b9b2d1e9e20978..3541c3a1c649b5 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.schema.yaml @@ -36,7 +36,7 @@ paths: description: Sort order required: false schema: - $ref: '#/components/schemas/SortOrder' + $ref: '../common_attributes.schema.yaml#/components/schemas/SortOrder' - name: 'page' in: query description: Page number @@ -101,9 +101,3 @@ components: - 'allowed' - 'field' - 'updated_at' - - SortOrder: - type: string - enum: - - 'asc' - - 'desc' diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts index d4d4ce5657f62b..613d54fa080fb7 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts @@ -45,3 +45,8 @@ export const User = z.object({ */ name: z.string().optional(), }); + +export type SortOrder = z.infer; +export const SortOrder = z.enum(['asc', 'desc']); +export type SortOrderEnum = typeof SortOrder.enum; +export const SortOrderEnum = SortOrder.enum; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml index 5c580c52281add..348868746fb6ce 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml @@ -28,3 +28,9 @@ components: type: string description: User name + SortOrder: + type: string + enum: + - 'asc' + - 'desc' + diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts index 556dca3db82142..6f8607640e2629 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts @@ -17,6 +17,7 @@ import { z } from 'zod'; import { ArrayFromString } from '@kbn/zod-helpers'; +import { SortOrder } from '../common_attributes.gen'; import { ConversationResponse } from './common_attributes.gen'; export type FindConversationsSortField = z.infer; @@ -29,11 +30,6 @@ export const FindConversationsSortField = z.enum([ export type FindConversationsSortFieldEnum = typeof FindConversationsSortField.enum; export const FindConversationsSortFieldEnum = FindConversationsSortField.enum; -export type SortOrder = z.infer; -export const SortOrder = z.enum(['asc', 'desc']); -export type SortOrderEnum = typeof SortOrder.enum; -export const SortOrderEnum = SortOrder.enum; - export type FindConversationsRequestQuery = z.infer; export const FindConversationsRequestQuery = z.object({ fields: ArrayFromString(z.string()).optional(), diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.schema.yaml index 44cec1a169e515..fcb4c0a013eaa3 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.schema.yaml @@ -36,7 +36,7 @@ paths: description: Sort order required: false schema: - $ref: '#/components/schemas/SortOrder' + $ref: '../common_attributes.schema.yaml#/components/schemas/SortOrder' - name: 'page' in: query description: Page number @@ -124,7 +124,7 @@ paths: description: Sort order required: false schema: - $ref: '#/components/schemas/SortOrder' + $ref: '../common_attributes.schema.yaml#/components/schemas/SortOrder' - name: 'page' in: query description: Page number @@ -188,9 +188,3 @@ components: - 'is_default' - 'title' - 'updated_at' - - SortOrder: - type: string - enum: - - 'asc' - - 'desc' diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/index.ts index c9c2d2a8be3c09..ae66432af3076f 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/index.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/index.ts @@ -45,3 +45,4 @@ export * from './knowledge_base/crud_kb_route.gen'; export * from './knowledge_base/bulk_crud_knowledge_base_route.gen'; export * from './knowledge_base/common_attributes.gen'; export * from './knowledge_base/crud_knowledge_base_route.gen'; +export * from './knowledge_base/find_knowledge_base_entries_route.gen'; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.schema.yaml index 63fcdf16b8fb19..53c69426b69bd9 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.schema.yaml @@ -121,4 +121,3 @@ components: type: string description: Knowledge Base Entry content - diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts new file mode 100644 index 00000000000000..25db35693c3dc8 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts @@ -0,0 +1,69 @@ +/* + * 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. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Find Knowledge Base Entries API endpoint + * version: 1 + */ + +import { z } from 'zod'; +import { ArrayFromString } from '@kbn/zod-helpers'; + +import { SortOrder } from '../common_attributes.gen'; +import { KnowledgeBaseEntryResponse } from './common_attributes.gen'; + +export type FindKnowledgeBaseEntriesSortField = z.infer; +export const FindKnowledgeBaseEntriesSortField = z.enum([ + 'created_at', + 'is_default', + 'title', + 'updated_at', +]); +export type FindKnowledgeBaseEntriesSortFieldEnum = typeof FindKnowledgeBaseEntriesSortField.enum; +export const FindKnowledgeBaseEntriesSortFieldEnum = FindKnowledgeBaseEntriesSortField.enum; + +export type FindKnowledgeBaseEntriesRequestQuery = z.infer< + typeof FindKnowledgeBaseEntriesRequestQuery +>; +export const FindKnowledgeBaseEntriesRequestQuery = z.object({ + fields: ArrayFromString(z.string()).optional(), + /** + * Search query + */ + filter: z.string().optional(), + /** + * Field to sort by + */ + sort_field: FindKnowledgeBaseEntriesSortField.optional(), + /** + * Sort order + */ + sort_order: SortOrder.optional(), + /** + * Page number + */ + page: z.coerce.number().int().min(1).optional().default(1), + /** + * Knowledge Base Entries per page + */ + per_page: z.coerce.number().int().min(0).optional().default(20), +}); +export type FindKnowledgeBaseEntriesRequestQueryInput = z.input< + typeof FindKnowledgeBaseEntriesRequestQuery +>; + +export type FindKnowledgeBaseEntriesResponse = z.infer; +export const FindKnowledgeBaseEntriesResponse = z.object({ + page: z.number().int(), + perPage: z.number().int(), + total: z.number().int(), + data: z.array(KnowledgeBaseEntryResponse), +}); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.schema.yaml new file mode 100644 index 00000000000000..d5298ff2ccbdc5 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.schema.yaml @@ -0,0 +1,102 @@ +openapi: 3.0.0 +info: + title: Find Knowledge Base Entries API endpoint + version: '1' +paths: + /internal/elastic_assistant/knowledge_base/entries/_find: + get: + operationId: FindKnowledgeBaseEntries + x-codegen-enabled: true + description: Finds Knowledge Base Entries that match the given query. + summary: Finds Knowledge Base Entries that match the given query. + tags: + - Knowledge Base Entries API + parameters: + - name: 'fields' + in: query + required: false + schema: + type: array + items: + type: string + - name: 'filter' + in: query + description: Search query + required: false + schema: + type: string + - name: 'sort_field' + in: query + description: Field to sort by + required: false + schema: + $ref: '#/components/schemas/FindKnowledgeBaseEntriesSortField' + - name: 'sort_order' + in: query + description: Sort order + required: false + schema: + $ref: '../common_attributes.schema.yaml#/components/schemas/SortOrder' + - name: 'page' + in: query + description: Page number + required: false + schema: + type: integer + minimum: 1 + default: 1 + - name: 'per_page' + in: query + description: Knowledge Base Entries per page + required: false + schema: + type: integer + minimum: 0 + default: 20 + + responses: + 200: + description: Successful response + content: + application/json: + schema: + type: object + properties: + page: + type: integer + perPage: + type: integer + total: + type: integer + data: + type: array + items: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryResponse' + required: + - page + - perPage + - total + - data + 400: + description: Generic Error + content: + application/json: + schema: + type: object + properties: + statusCode: + type: number + error: + type: string + message: + type: string + +components: + schemas: + FindKnowledgeBaseEntriesSortField: + type: string + enum: + - 'created_at' + - 'is_default' + - 'title' + - 'updated_at' diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.gen.ts index bd050f5c8260db..49f4c75029581f 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.gen.ts @@ -17,6 +17,7 @@ import { z } from 'zod'; import { ArrayFromString } from '@kbn/zod-helpers'; +import { SortOrder } from '../common_attributes.gen'; import { PromptResponse } from './bulk_crud_prompts_route.gen'; export type FindPromptsSortField = z.infer; @@ -24,11 +25,6 @@ export const FindPromptsSortField = z.enum(['created_at', 'is_default', 'name', export type FindPromptsSortFieldEnum = typeof FindPromptsSortField.enum; export const FindPromptsSortFieldEnum = FindPromptsSortField.enum; -export type SortOrder = z.infer; -export const SortOrder = z.enum(['asc', 'desc']); -export type SortOrderEnum = typeof SortOrder.enum; -export const SortOrderEnum = SortOrder.enum; - export type FindPromptsRequestQuery = z.infer; export const FindPromptsRequestQuery = z.object({ fields: ArrayFromString(z.string()).optional(), diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.schema.yaml index 8e85194811dbc1..1902f4e9ae3d99 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.schema.yaml @@ -36,7 +36,7 @@ paths: description: Sort order required: false schema: - $ref: '#/components/schemas/SortOrder' + $ref: '../common_attributes.schema.yaml#/components/schemas/SortOrder' - name: 'page' in: query description: Page number @@ -100,9 +100,3 @@ components: - 'is_default' - 'name' - 'updated_at' - - SortOrder: - type: string - enum: - - 'asc' - - 'desc' diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx index 0182c4061866b0..0e89bc7f5738a0 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx @@ -9,13 +9,7 @@ import { HttpSetup } from '@kbn/core-http-browser'; import { ApiConfig } from '@kbn/elastic-assistant-common'; import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/public/common'; -import { - deleteKnowledgeBase, - fetchConnectorExecuteAction, - FetchConnectorExecuteAction, - getKnowledgeBaseStatus, - postKnowledgeBase, -} from '.'; +import { fetchConnectorExecuteAction, FetchConnectorExecuteAction } from '.'; import { API_ERROR } from '../translations'; jest.mock('@kbn/core-http-browser'); @@ -303,79 +297,4 @@ describe('API tests', () => { expect(result).toEqual({ response, isStream: false, isError: false }); }); }); - - const knowledgeBaseArgs = { - resource: 'a-resource', - http: mockHttp, - }; - describe('getKnowledgeBaseStatus', () => { - it('calls the knowledge base API when correct resource path', async () => { - await getKnowledgeBaseStatus(knowledgeBaseArgs); - - expect(mockHttp.fetch).toHaveBeenCalledWith( - '/internal/elastic_assistant/knowledge_base/a-resource', - { - method: 'GET', - signal: undefined, - version: '1', - } - ); - }); - it('returns error when error is an error', async () => { - const error = 'simulated error'; - (mockHttp.fetch as jest.Mock).mockImplementation(() => { - throw new Error(error); - }); - - await expect(getKnowledgeBaseStatus(knowledgeBaseArgs)).resolves.toThrowError( - 'simulated error' - ); - }); - }); - - describe('postKnowledgeBase', () => { - it('calls the knowledge base API when correct resource path', async () => { - await postKnowledgeBase(knowledgeBaseArgs); - - expect(mockHttp.fetch).toHaveBeenCalledWith( - '/internal/elastic_assistant/knowledge_base/a-resource', - { - method: 'POST', - signal: undefined, - version: '1', - } - ); - }); - it('returns error when error is an error', async () => { - const error = 'simulated error'; - (mockHttp.fetch as jest.Mock).mockImplementation(() => { - throw new Error(error); - }); - - await expect(postKnowledgeBase(knowledgeBaseArgs)).resolves.toThrowError('simulated error'); - }); - }); - - describe('deleteKnowledgeBase', () => { - it('calls the knowledge base API when correct resource path', async () => { - await deleteKnowledgeBase(knowledgeBaseArgs); - - expect(mockHttp.fetch).toHaveBeenCalledWith( - '/internal/elastic_assistant/knowledge_base/a-resource', - { - method: 'DELETE', - signal: undefined, - version: '1', - } - ); - }); - it('returns error when error is an error', async () => { - const error = 'simulated error'; - (mockHttp.fetch as jest.Mock).mockImplementation(() => { - throw new Error(error); - }); - - await expect(deleteKnowledgeBase(knowledgeBaseArgs)).resolves.toThrowError('simulated error'); - }); - }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx index a554324515ad62..b8c42a787621b8 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx @@ -6,19 +6,7 @@ */ import { HttpSetup } from '@kbn/core/public'; -import { IHttpFetchError } from '@kbn/core-http-browser'; -import { - API_VERSIONS, - ApiConfig, - CreateKnowledgeBaseRequestParams, - CreateKnowledgeBaseResponse, - DeleteKnowledgeBaseRequestParams, - DeleteKnowledgeBaseResponse, - ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, - ReadKnowledgeBaseRequestParams, - ReadKnowledgeBaseResponse, - Replacements, -} from '@kbn/elastic-assistant-common'; +import { API_VERSIONS, ApiConfig, Replacements } from '@kbn/elastic-assistant-common'; import { API_ERROR } from '../translations'; import { getOptionalRequestParams } from '../helpers'; import { TraceOptions } from '../types'; @@ -185,99 +173,3 @@ export const fetchConnectorExecuteAction = async ({ }; } }; - -/** - * API call for getting the status of the Knowledge Base. Provide - * a resource to include the status of that specific resource. - * - * @param {Object} options - The options object. - * @param {HttpSetup} options.http - HttpSetup - * @param {string} [options.resource] - Resource to get the status of, otherwise status of overall KB - * @param {AbortSignal} [options.signal] - AbortSignal - * - * @returns {Promise} - */ -export const getKnowledgeBaseStatus = async ({ - http, - resource, - signal, -}: ReadKnowledgeBaseRequestParams & { http: HttpSetup; signal?: AbortSignal | undefined }): Promise< - ReadKnowledgeBaseResponse | IHttpFetchError -> => { - try { - const path = ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL.replace('{resource?}', resource || ''); - const response = await http.fetch(path, { - method: 'GET', - signal, - version: API_VERSIONS.internal.v1, - }); - - return response as ReadKnowledgeBaseResponse; - } catch (error) { - return error as IHttpFetchError; - } -}; - -/** - * API call for setting up the Knowledge Base. Provide a resource to set up a specific resource. - * - * @param {Object} options - The options object. - * @param {HttpSetup} options.http - HttpSetup - * @param {string} [options.resource] - Resource to be added to the KB, otherwise sets up the base KB - * @param {AbortSignal} [options.signal] - AbortSignal - * - * @returns {Promise} - */ -export const postKnowledgeBase = async ({ - http, - resource, - signal, -}: CreateKnowledgeBaseRequestParams & { - http: HttpSetup; - signal?: AbortSignal | undefined; -}): Promise => { - try { - const path = ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL.replace('{resource?}', resource || ''); - const response = await http.fetch(path, { - method: 'POST', - signal, - version: API_VERSIONS.internal.v1, - }); - - return response as CreateKnowledgeBaseResponse; - } catch (error) { - return error as IHttpFetchError; - } -}; - -/** - * API call for deleting the Knowledge Base. Provide a resource to delete that specific resource. - * - * @param {Object} options - The options object. - * @param {HttpSetup} options.http - HttpSetup - * @param {string} [options.resource] - Resource to be deleted from the KB, otherwise delete the entire KB - * @param {AbortSignal} [options.signal] - AbortSignal - * - * @returns {Promise} - */ -export const deleteKnowledgeBase = async ({ - http, - resource, - signal, -}: DeleteKnowledgeBaseRequestParams & { - http: HttpSetup; - signal?: AbortSignal | undefined; -}): Promise => { - try { - const path = ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL.replace('{resource?}', resource || ''); - const response = await http.fetch(path, { - method: 'DELETE', - signal, - version: API_VERSIONS.internal.v1, - }); - - return response as DeleteKnowledgeBaseResponse; - } catch (error) { - return error as IHttpFetchError; - } -}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/api.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/api.test.tsx new file mode 100644 index 00000000000000..06ba7d875b64f0 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/api.test.tsx @@ -0,0 +1,97 @@ +/* + * 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 { HttpSetup } from '@kbn/core-http-browser'; + +import { deleteKnowledgeBase, getKnowledgeBaseStatus, postKnowledgeBase } from './api'; + +jest.mock('@kbn/core-http-browser'); + +const mockHttp = { + fetch: jest.fn(), +} as unknown as HttpSetup; + +describe('API tests', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + const knowledgeBaseArgs = { + resource: 'a-resource', + http: mockHttp, + }; + describe('getKnowledgeBaseStatus', () => { + it('calls the knowledge base API when correct resource path', async () => { + await getKnowledgeBaseStatus(knowledgeBaseArgs); + + expect(mockHttp.fetch).toHaveBeenCalledWith( + '/internal/elastic_assistant/knowledge_base/a-resource', + { + method: 'GET', + signal: undefined, + version: '1', + } + ); + }); + it('returns error when error is an error', async () => { + const error = 'simulated error'; + (mockHttp.fetch as jest.Mock).mockImplementation(() => { + throw new Error(error); + }); + + await expect(getKnowledgeBaseStatus(knowledgeBaseArgs)).resolves.toThrowError( + 'simulated error' + ); + }); + }); + + describe('postKnowledgeBase', () => { + it('calls the knowledge base API when correct resource path', async () => { + await postKnowledgeBase(knowledgeBaseArgs); + + expect(mockHttp.fetch).toHaveBeenCalledWith( + '/internal/elastic_assistant/knowledge_base/a-resource', + { + method: 'POST', + signal: undefined, + version: '1', + } + ); + }); + it('returns error when error is an error', async () => { + const error = 'simulated error'; + (mockHttp.fetch as jest.Mock).mockImplementation(() => { + throw new Error(error); + }); + + await expect(postKnowledgeBase(knowledgeBaseArgs)).resolves.toThrowError('simulated error'); + }); + }); + + describe('deleteKnowledgeBase', () => { + it('calls the knowledge base API when correct resource path', async () => { + await deleteKnowledgeBase(knowledgeBaseArgs); + + expect(mockHttp.fetch).toHaveBeenCalledWith( + '/internal/elastic_assistant/knowledge_base/a-resource', + { + method: 'DELETE', + signal: undefined, + version: '1', + } + ); + }); + it('returns error when error is an error', async () => { + const error = 'simulated error'; + (mockHttp.fetch as jest.Mock).mockImplementation(() => { + throw new Error(error); + }); + + await expect(deleteKnowledgeBase(knowledgeBaseArgs)).resolves.toThrowError('simulated error'); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/api.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/api.tsx new file mode 100644 index 00000000000000..65fa1f72064e11 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/api.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 { + API_VERSIONS, + CreateKnowledgeBaseRequestParams, + CreateKnowledgeBaseResponse, + DeleteKnowledgeBaseRequestParams, + DeleteKnowledgeBaseResponse, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, + ReadKnowledgeBaseRequestParams, + ReadKnowledgeBaseResponse, +} from '@kbn/elastic-assistant-common'; +import { HttpSetup, IHttpFetchError } from '@kbn/core-http-browser'; + +/** + * API call for getting the status of the Knowledge Base. Provide + * a resource to include the status of that specific resource. + * + * @param {Object} options - The options object. + * @param {HttpSetup} options.http - HttpSetup + * @param {string} [options.resource] - Resource to get the status of, otherwise status of overall KB + * @param {AbortSignal} [options.signal] - AbortSignal + * + * @returns {Promise} + */ +export const getKnowledgeBaseStatus = async ({ + http, + resource, + signal, +}: ReadKnowledgeBaseRequestParams & { http: HttpSetup; signal?: AbortSignal | undefined }): Promise< + ReadKnowledgeBaseResponse | IHttpFetchError +> => { + try { + const path = ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL.replace('{resource?}', resource || ''); + const response = await http.fetch(path, { + method: 'GET', + signal, + version: API_VERSIONS.internal.v1, + }); + + return response as ReadKnowledgeBaseResponse; + } catch (error) { + return error as IHttpFetchError; + } +}; + +/** + * API call for setting up the Knowledge Base. Provide a resource to set up a specific resource. + * + * @param {Object} options - The options object. + * @param {HttpSetup} options.http - HttpSetup + * @param {string} [options.resource] - Resource to be added to the KB, otherwise sets up the base KB + * @param {AbortSignal} [options.signal] - AbortSignal + * + * @returns {Promise} + */ +export const postKnowledgeBase = async ({ + http, + resource, + signal, +}: CreateKnowledgeBaseRequestParams & { + http: HttpSetup; + signal?: AbortSignal | undefined; +}): Promise => { + try { + const path = ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL.replace('{resource?}', resource || ''); + const response = await http.fetch(path, { + method: 'POST', + signal, + version: API_VERSIONS.internal.v1, + }); + + return response as CreateKnowledgeBaseResponse; + } catch (error) { + return error as IHttpFetchError; + } +}; + +/** + * API call for deleting the Knowledge Base. Provide a resource to delete that specific resource. + * + * @param {Object} options - The options object. + * @param {HttpSetup} options.http - HttpSetup + * @param {string} [options.resource] - Resource to be deleted from the KB, otherwise delete the entire KB + * @param {AbortSignal} [options.signal] - AbortSignal + * + * @returns {Promise} + */ +export const deleteKnowledgeBase = async ({ + http, + resource, + signal, +}: DeleteKnowledgeBaseRequestParams & { + http: HttpSetup; + signal?: AbortSignal | undefined; +}): Promise => { + try { + const path = ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL.replace('{resource?}', resource || ''); + const response = await http.fetch(path, { + method: 'DELETE', + signal, + version: API_VERSIONS.internal.v1, + }); + + return response as DeleteKnowledgeBaseResponse; + } catch (error) { + return error as IHttpFetchError; + } +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_create_knowledge_base_entry.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_create_knowledge_base_entry.tsx new file mode 100644 index 00000000000000..eaf9a32fde81a6 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_create_knowledge_base_entry.tsx @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMutation } from '@tanstack/react-query'; +import type { HttpSetup, IHttpFetchError, ResponseErrorBody } from '@kbn/core-http-browser'; +import type { IToasts } from '@kbn/core-notifications-browser'; +import { i18n } from '@kbn/i18n'; + +import { + API_VERSIONS, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL, + KnowledgeBaseEntryCreateProps, + KnowledgeBaseEntryResponse, +} from '@kbn/elastic-assistant-common'; +import { useInvalidateKnowledgeBaseEntries } from './use_knowledge_base_entries'; + +const CREATE_KNOWLEDGE_BASE_ENTRY_MUTATION_KEY = [ + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL, + API_VERSIONS.internal.v1, +]; + +export interface UseCreateKnowledgeBaseEntryParams { + http: HttpSetup; + signal?: AbortSignal; + toasts?: IToasts; +} + +/** + * Hook for creating a Knowledge Base Entry + * + * @param {Object} options - The options object + * @param {HttpSetup} options.http - HttpSetup + * @param {AbortSignal} [options.signal] - AbortSignal + * @param {IToasts} [options.toasts] - IToasts + * + * @returns mutation hook for creating a Knowledge Base Entry + * + */ +export const useCreateKnowledgeBaseEntry = ({ + http, + signal, + toasts, +}: UseCreateKnowledgeBaseEntryParams) => { + const invalidateKnowledgeBaseEntries = useInvalidateKnowledgeBaseEntries(); + + return useMutation( + CREATE_KNOWLEDGE_BASE_ENTRY_MUTATION_KEY, + (entry: KnowledgeBaseEntryCreateProps) => { + return http.post( + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL, + { + body: JSON.stringify(entry), + version: API_VERSIONS.internal.v1, + signal, + } + ); + }, + { + onError: (error: IHttpFetchError) => { + if (error.name !== 'AbortError') { + toasts?.addError( + error.body && error.body.message ? new Error(error.body.message) : error, + { + title: i18n.translate( + 'xpack.elasticAssistant.knowledgeBase.entries.createErrorTitle', + { + defaultMessage: 'Error creating Knowledge Base Entry', + } + ), + } + ); + } + }, + onSettled: () => { + invalidateKnowledgeBaseEntries(); + }, + } + ); +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_delete_knowledge_base_entries.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_delete_knowledge_base_entries.tsx new file mode 100644 index 00000000000000..0cfce8f576b243 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_delete_knowledge_base_entries.tsx @@ -0,0 +1,90 @@ +/* + * 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 { useMutation } from '@tanstack/react-query'; +import type { HttpSetup, IHttpFetchError, ResponseErrorBody } from '@kbn/core-http-browser'; +import type { IToasts } from '@kbn/core-notifications-browser'; +import { i18n } from '@kbn/i18n'; + +import { + API_VERSIONS, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION, + KnowledgeBaseEntryBulkActionBase, + KnowledgeBaseEntryBulkCrudActionResponse, + PerformKnowledgeBaseEntryBulkActionRequestBody, +} from '@kbn/elastic-assistant-common'; +import { useInvalidateKnowledgeBaseEntries } from './use_knowledge_base_entries'; + +const DELETE_KNOWLEDGE_BASE_ENTRIES_MUTATION_KEY = [ + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION, + API_VERSIONS.internal.v1, +]; + +export interface UseDeleteKnowledgeEntriesParams { + http: HttpSetup; + signal?: AbortSignal; + toasts?: IToasts; +} + +/** + * Hook for deleting Knowledge Base Entries by id or query. + * + * @param {Object} options - The options object + * @param {HttpSetup} options.http - HttpSetup + * @param {AbortSignal} [options.signal] - AbortSignal + * @param {IToasts} [options.toasts] - IToasts + * + * @returns mutation hook for deleting Knowledge Base Entries + * + */ +export const useDeleteKnowledgeBaseEntries = ({ + http, + signal, + toasts, +}: UseDeleteKnowledgeEntriesParams) => { + const invalidateKnowledgeBaseEntries = useInvalidateKnowledgeBaseEntries(); + + return useMutation( + DELETE_KNOWLEDGE_BASE_ENTRIES_MUTATION_KEY, + ({ ids, query }: KnowledgeBaseEntryBulkActionBase) => { + const body: PerformKnowledgeBaseEntryBulkActionRequestBody = { + delete: { + query, + ids, + }, + }; + return http.post( + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION, + { + body: JSON.stringify(body), + version: API_VERSIONS.internal.v1, + signal, + } + ); + }, + { + onError: (error: IHttpFetchError) => { + if (error.name !== 'AbortError') { + toasts?.addError( + error.body && error.body.message ? new Error(error.body.message) : error, + { + title: i18n.translate( + 'xpack.elasticAssistant.knowledgeBase.entries.deleteErrorTitle', + { + defaultMessage: 'Error deleting Knowledge Base Entries', + } + ), + } + ); + } + }, + onSettled: () => { + invalidateKnowledgeBaseEntries(); + }, + } + ); +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_knowledge_base_entries.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_knowledge_base_entries.ts new file mode 100644 index 00000000000000..aa1d72d755ffa4 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/entries/use_knowledge_base_entries.ts @@ -0,0 +1,80 @@ +/* + * 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 { HttpSetup } from '@kbn/core/public'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { + API_VERSIONS, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_FIND, + FindKnowledgeBaseEntriesResponse, +} from '@kbn/elastic-assistant-common'; + +import { useCallback } from 'react'; + +export interface UseKnowledgeBaseEntriesParams { + http: HttpSetup; + signal?: AbortSignal | undefined; +} + +/** + * Hook for fetching Knowledge Base Entries. + * + * Note: RBAC is handled at kbDataClient layer, so unless user has KB feature privileges, this will only return system and their own user KB entries. + * + * @param {Object} options - The options object. + * @param {HttpSetup} options.http - HttpSetup + * @param {Function} [options.onFetch] - transformation function for kb entries fetch result + * @param {AbortSignal} [options.signal] - AbortSignal + * + * @returns {useQuery} hook for fetching Knowledge Base Entries + */ +const query = { + page: 1, + perPage: 100, +}; + +export const KNOWLEDGE_BASE_ENTRY_QUERY_KEY = [ + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_FIND, + query.page, + query.perPage, + API_VERSIONS.internal.v1, +]; + +export const useKnowledgeBaseEntries = ({ http, signal }: UseKnowledgeBaseEntriesParams) => + useQuery( + KNOWLEDGE_BASE_ENTRY_QUERY_KEY, + async () => + http.fetch( + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_FIND, + { + method: 'GET', + version: API_VERSIONS.internal.v1, + query, + signal, + } + ), + { + keepPreviousData: true, + initialData: { page: 1, perPage: 100, total: 0, data: [] }, + } + ); + +/** + * Use this hook to invalidate the Knowledge Base Entries cache. For example, adding, + * editing, or deleting any Knowledge Base entries should lead to cache invalidation. + * + * @returns {Function} - Function to invalidate the Knowledge Base Entries cache + */ +export const useInvalidateKnowledgeBaseEntries = () => { + const queryClient = useQueryClient(); + + return useCallback(() => { + queryClient.invalidateQueries(KNOWLEDGE_BASE_ENTRY_QUERY_KEY, { + refetchType: 'active', + }); + }, [queryClient]); +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_delete_knowledge_base.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_delete_knowledge_base.test.tsx similarity index 94% rename from x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_delete_knowledge_base.test.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_delete_knowledge_base.test.tsx index 06933c4ebeff90..b50c345edb3b39 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_delete_knowledge_base.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_delete_knowledge_base.test.tsx @@ -7,14 +7,14 @@ import { act, renderHook } from '@testing-library/react-hooks'; import { useDeleteKnowledgeBase, UseDeleteKnowledgeBaseParams } from './use_delete_knowledge_base'; -import { deleteKnowledgeBase as _deleteKnowledgeBase } from '../assistant/api'; +import { deleteKnowledgeBase as _deleteKnowledgeBase } from './api'; import { useMutation as _useMutation } from '@tanstack/react-query'; const useMutationMock = _useMutation as jest.Mock; const deleteKnowledgeBaseMock = _deleteKnowledgeBase as jest.Mock; -jest.mock('../assistant/api', () => { - const actual = jest.requireActual('../assistant/api'); +jest.mock('./api', () => { + const actual = jest.requireActual('./api'); return { ...actual, deleteKnowledgeBase: jest.fn((...args) => actual.deleteKnowledgeBase(...args)), diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_delete_knowledge_base.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_delete_knowledge_base.tsx similarity index 97% rename from x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_delete_knowledge_base.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_delete_knowledge_base.tsx index 3266bc20b8cdd5..5e4ce82bde3bd7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_delete_knowledge_base.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_delete_knowledge_base.tsx @@ -9,7 +9,7 @@ import { useMutation } from '@tanstack/react-query'; import type { IToasts } from '@kbn/core-notifications-browser'; import type { HttpSetup, IHttpFetchError, ResponseErrorBody } from '@kbn/core-http-browser'; import { i18n } from '@kbn/i18n'; -import { deleteKnowledgeBase } from '../assistant/api'; +import { deleteKnowledgeBase } from './api'; import { useInvalidateKnowledgeBaseStatus } from './use_knowledge_base_status'; const DELETE_KNOWLEDGE_BASE_MUTATION_KEY = ['elastic-assistant', 'delete-knowledge-base']; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx similarity index 96% rename from x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.test.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx index a9996668453784..aaad50afacd919 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.test.tsx @@ -7,12 +7,12 @@ import { act, renderHook } from '@testing-library/react-hooks'; import { useKnowledgeBaseStatus, UseKnowledgeBaseStatusParams } from './use_knowledge_base_status'; -import { getKnowledgeBaseStatus as _getKnowledgeBaseStatus } from '../assistant/api'; +import { getKnowledgeBaseStatus as _getKnowledgeBaseStatus } from './api'; const getKnowledgeBaseStatusMock = _getKnowledgeBaseStatus as jest.Mock; -jest.mock('../assistant/api', () => { - const actual = jest.requireActual('../assistant/api'); +jest.mock('./api', () => { + const actual = jest.requireActual('./api'); return { ...actual, getKnowledgeBaseStatus: jest.fn((...args) => actual.getKnowledgeBaseStatus(...args)), diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx similarity index 97% rename from x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx index c03eb31581e42e..ba6317329d350c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_knowledge_base_status.tsx @@ -12,7 +12,7 @@ import type { IToasts } from '@kbn/core-notifications-browser'; import { i18n } from '@kbn/i18n'; import { useCallback } from 'react'; import { ReadKnowledgeBaseResponse } from '@kbn/elastic-assistant-common'; -import { getKnowledgeBaseStatus } from '../assistant/api'; +import { getKnowledgeBaseStatus } from './api'; const KNOWLEDGE_BASE_STATUS_QUERY_KEY = ['elastic-assistant', 'knowledge-base-status']; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_setup_knowledge_base.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_setup_knowledge_base.test.tsx similarity index 94% rename from x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_setup_knowledge_base.test.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_setup_knowledge_base.test.tsx index 8e0b084e9beeda..a252700ba744f4 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_setup_knowledge_base.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_setup_knowledge_base.test.tsx @@ -7,13 +7,13 @@ import { act, renderHook } from '@testing-library/react-hooks'; import { useSetupKnowledgeBase, UseSetupKnowledgeBaseParams } from './use_setup_knowledge_base'; -import { postKnowledgeBase as _postKnowledgeBase } from '../assistant/api'; +import { postKnowledgeBase as _postKnowledgeBase } from './api'; import { useMutation as _useMutation } from '@tanstack/react-query'; const postKnowledgeBaseMock = _postKnowledgeBase as jest.Mock; const useMutationMock = _useMutation as jest.Mock; -jest.mock('../assistant/api', () => { - const actual = jest.requireActual('../assistant/api'); +jest.mock('./api', () => { + const actual = jest.requireActual('./api'); return { ...actual, postKnowledgeBase: jest.fn((...args) => actual.postKnowledgeBase(...args)), diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_setup_knowledge_base.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_setup_knowledge_base.tsx similarity index 97% rename from x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_setup_knowledge_base.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_setup_knowledge_base.tsx index 34533683e79212..c27c97976e9894 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_setup_knowledge_base.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/knowledge_base/use_setup_knowledge_base.tsx @@ -9,7 +9,7 @@ import { useMutation } from '@tanstack/react-query'; import type { HttpSetup, IHttpFetchError, ResponseErrorBody } from '@kbn/core-http-browser'; import type { IToasts } from '@kbn/core-notifications-browser'; import { i18n } from '@kbn/i18n'; -import { postKnowledgeBase } from '../assistant/api'; +import { postKnowledgeBase } from './api'; import { useInvalidateKnowledgeBaseStatus } from './use_knowledge_base_status'; const SETUP_KNOWLEDGE_BASE_MUTATION_KEY = ['elastic-assistant', 'post-knowledge-base']; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/install_knowledge_base_button.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/install_knowledge_base_button.tsx index f5a82fd02c55db..32e34eb59fa939 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/install_knowledge_base_button.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/install_knowledge_base_button.tsx @@ -10,8 +10,8 @@ import { EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useAssistantContext } from '../..'; -import { useSetupKnowledgeBase } from './use_setup_knowledge_base'; -import { useKnowledgeBaseStatus } from './use_knowledge_base_status'; +import { useSetupKnowledgeBase } from '../assistant/api/knowledge_base/use_setup_knowledge_base'; +import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_knowledge_base_status'; const ESQL_RESOURCE = 'esql'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx index 56f6796ac16fa3..4d39504075c7e7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx @@ -11,7 +11,7 @@ import { fireEvent, render } from '@testing-library/react'; import { DEFAULT_LATEST_ALERTS } from '../assistant_context/constants'; import { KnowledgeBaseSettings } from './knowledge_base_settings'; import { TestProviders } from '../mock/test_providers/test_providers'; -import { useKnowledgeBaseStatus } from './use_knowledge_base_status'; +import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_knowledge_base_status'; import { mockSystemPrompts } from '../mock/system_prompt'; import { defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; @@ -47,7 +47,7 @@ const defaultProps = { setUpdatedKnowledgeBaseSettings, }; const mockDelete = jest.fn(); -jest.mock('./use_delete_knowledge_base', () => ({ +jest.mock('../assistant/api/knowledge_base/use_delete_knowledge_base', () => ({ useDeleteKnowledgeBase: jest.fn(() => { return { mutate: mockDelete, @@ -57,7 +57,7 @@ jest.mock('./use_delete_knowledge_base', () => ({ })); const mockSetup = jest.fn(); -jest.mock('./use_setup_knowledge_base', () => ({ +jest.mock('../assistant/api/knowledge_base/use_setup_knowledge_base', () => ({ useSetupKnowledgeBase: jest.fn(() => { return { mutate: mockSetup, @@ -66,7 +66,7 @@ jest.mock('./use_setup_knowledge_base', () => ({ }), })); -jest.mock('./use_knowledge_base_status', () => ({ +jest.mock('../assistant/api/knowledge_base/use_knowledge_base_status', () => ({ useKnowledgeBaseStatus: jest.fn(() => { return { data: { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx index 8c83d1f3403e8a..fc152d1e5a3daf 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx @@ -30,9 +30,9 @@ import { AlertsSettings } from '../alerts/settings/alerts_settings'; import { useAssistantContext } from '../assistant_context'; import type { KnowledgeBaseConfig } from '../assistant/types'; import * as i18n from './translations'; -import { useDeleteKnowledgeBase } from './use_delete_knowledge_base'; -import { useKnowledgeBaseStatus } from './use_knowledge_base_status'; -import { useSetupKnowledgeBase } from './use_setup_knowledge_base'; +import { useDeleteKnowledgeBase } from '../assistant/api/knowledge_base/use_delete_knowledge_base'; +import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_knowledge_base_status'; +import { useSetupKnowledgeBase } from '../assistant/api/knowledge_base/use_setup_knowledge_base'; const ESQL_RESOURCE = 'esql'; const KNOWLEDGE_BASE_INDEX_PATTERN_OLD = '.kibana-elastic-ai-assistant-kb'; diff --git a/x-pack/plugins/elastic_assistant/common/constants.ts b/x-pack/plugins/elastic_assistant/common/constants.ts index 5c5233eaaa6c8a..d8c2630c1aef80 100755 --- a/x-pack/plugins/elastic_assistant/common/constants.ts +++ b/x-pack/plugins/elastic_assistant/common/constants.ts @@ -27,6 +27,9 @@ export const ANONYMIZATION_FIELDS_TABLE_MAX_PAGE_SIZE = 100; export const MAX_PROMPTS_TO_UPDATE_IN_PARALLEL = 50; export const PROMPTS_TABLE_MAX_PAGE_SIZE = 100; +// Knowledge Base +export const KNOWLEDGE_BASE_ENTRIES_TABLE_MAX_PAGE_SIZE = 100; + // Capabilities export const CAPABILITIES = `${BASE_PATH}/capabilities`; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts index 1e867ac4ae4680..680ab17672f61e 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts @@ -16,6 +16,7 @@ import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-ser import { KnowledgeBaseEntryCreateProps, KnowledgeBaseEntryResponse, + Metadata, } from '@kbn/elastic-assistant-common'; import pRetry from 'p-retry'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; @@ -221,12 +222,12 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { /** * Adds LangChain Documents to the knowledge base * - * @param documents LangChain Documents to add to the knowledge base + * @param {Array>} documents - LangChain Documents to add to the knowledge base */ public addKnowledgeBaseDocuments = async ({ documents, }: { - documents: Document[]; + documents: Array>; }): Promise => { const writer = await this.getWriter(); const changedAt = new Date().toISOString(); @@ -240,9 +241,8 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { const { errors, docs_created: docsCreated } = await writer.bulk({ documentsToCreate: documents.map((doc) => transformToCreateSchema(changedAt, this.spaceId, authenticatedUser, { - // TODO: Update the LangChain Document Metadata type extension metadata: { - kbResource: doc.metadata.kbResourcer ?? 'unknown', + kbResource: doc.metadata.kbResource ?? 'unknown', required: doc.metadata.required ?? false, source: doc.metadata.source ?? 'unknown', }, diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.ts index b34beb5c5aa9cc..3d4666cdf7540c 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/content_loaders/esql_loader.ts @@ -9,7 +9,9 @@ import { Logger } from '@kbn/core/server'; import { DirectoryLoader } from 'langchain/document_loaders/fs/directory'; import { TextLoader } from 'langchain/document_loaders/fs/text'; import { resolve } from 'path'; +import { Document } from 'langchain/document'; +import { Metadata } from '@kbn/elastic-assistant-common'; import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; import { addRequiredKbResourceMetadata } from './add_required_kb_resource_metadata'; import { ESQL_RESOURCE } from '../../../routes/knowledge_base/constants'; @@ -47,15 +49,15 @@ export const loadESQL = async (esStore: ElasticsearchStore, logger: Logger): Pro true ); - const docs = await docsLoader.load(); - const languageDocs = await languageLoader.load(); + const docs = (await docsLoader.load()) as Array>; + const languageDocs = (await languageLoader.load()) as Array>; const rawExampleQueries = await exampleQueriesLoader.load(); // Add additional metadata to the example queries that indicates they are required KB documents: const requiredExampleQueries = addRequiredKbResourceMetadata({ docs: rawExampleQueries, kbResource: ESQL_RESOURCE, - }); + }) as Array>; logger.info( `Loading ${docs.length} ES|QL docs, ${languageDocs.length} language docs, and ${requiredExampleQueries.length} example queries into the Knowledge Base` diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.test.ts index b38d4b82f48b4b..e45ad55999af69 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.test.ts @@ -25,6 +25,7 @@ import { KNOWLEDGE_BASE_EXECUTION_ERROR_EVENT, KNOWLEDGE_BASE_EXECUTION_SUCCESS_EVENT, } from '../../telemetry/event_based_telemetry'; +import { Metadata } from '@kbn/elastic-assistant-common'; jest.mock('uuid', () => ({ v4: jest.fn(), @@ -244,9 +245,9 @@ describe('ElasticsearchStore', () => { ], }); - const document = new Document({ + const document = new Document({ pageContent: 'interesting stuff', - metadata: { source: '1' }, + metadata: { kbResource: 'esql', required: false, source: '1' }, }); const docsInstalled = await esStore.addDocuments([document]); @@ -262,6 +263,8 @@ describe('ElasticsearchStore', () => { }, { metadata: { + kbResource: 'esql', + required: false, source: '1', }, text: 'interesting stuff', diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts index 86791cec5f5ce4..e076c90526a53b 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts @@ -17,6 +17,7 @@ import { Document } from 'langchain/document'; import { VectorStore } from '@langchain/core/vectorstores'; import * as uuid from 'uuid'; +import { Metadata } from '@kbn/elastic-assistant-common'; import { transformError } from '@kbn/securitysolution-es-utils'; import { ElasticsearchEmbeddings } from '../embeddings/elasticsearch_embeddings'; import { FlattenedHit, getFlattenedHits } from './helpers/get_flattened_hits'; @@ -105,7 +106,7 @@ export class ElasticsearchStore extends VectorStore { * @returns Promise of document IDs added to the store */ addDocuments = async ( - documents: Document[], + documents: Array>, options?: Record ): Promise => { // Code path for when `assistantKnowledgeBaseByDefault` FF is enabled @@ -145,7 +146,7 @@ export class ElasticsearchStore extends VectorStore { }; addDocumentsViaDataClient = async ( - documents: Document[], + documents: Array>, options?: Record ): Promise => { if (!this.kbDataClient) { diff --git a/x-pack/plugins/elastic_assistant/server/routes/helpers.ts b/x-pack/plugins/elastic_assistant/server/routes/helpers.ts index 932eafb4a549bd..243de14d67ed31 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/helpers.ts @@ -5,11 +5,15 @@ * 2.0. */ -import { KibanaRequest } from '@kbn/core-http-server'; +import { IKibanaResponse, KibanaRequest, KibanaResponseFactory } from '@kbn/core-http-server'; import { Logger } from '@kbn/core/server'; import { Message, TraceData } from '@kbn/elastic-assistant-common'; import { ILicense } from '@kbn/licensing-plugin/server'; +import { AwaitedProperties } from '@kbn/utility-types'; +import { AssistantFeatureKey } from '@kbn/elastic-assistant-common/impl/capabilities'; import { MINIMUM_AI_ASSISTANT_LICENSE } from '../../common/constants'; +import { ElasticAssistantRequestHandlerContext } from '../types'; +import { buildResponse } from './utils'; interface GetPluginNameFromRequestParams { request: KibanaRequest; @@ -87,3 +91,69 @@ export const hasAIAssistantLicense = (license: ILicense): boolean => export const UPGRADE_LICENSE_MESSAGE = 'Your license does not support AI Assistant. Please upgrade your license.'; + +interface PerformChecksParams { + authenticatedUser?: boolean; + capability?: AssistantFeatureKey; + context: AwaitedProperties< + Pick + >; + license?: boolean; + request: KibanaRequest; + response: KibanaResponseFactory; +} + +/** + * Helper to perform checks for authenticated user, capability, and license. Perform all or one + * of the checks by providing relevant optional params. Check order is license, authenticated user, + * then capability. + * + * @param authenticatedUser - Whether to check for an authenticated user + * @param capability - Specific capability to check if enabled, e.g. `assistantModelEvaluation` + * @param context - Route context + * @param license - Whether to check for a valid license + * @param request - Route KibanaRequest + * @param response - Route KibanaResponseFactory + */ +export const performChecks = ({ + authenticatedUser, + capability, + context, + license, + request, + response, +}: PerformChecksParams): IKibanaResponse | undefined => { + const assistantResponse = buildResponse(response); + + if (license) { + if (!hasAIAssistantLicense(context.licensing.license)) { + return response.forbidden({ + body: { + message: UPGRADE_LICENSE_MESSAGE, + }, + }); + } + } + + if (authenticatedUser) { + if (context.elasticAssistant.getCurrentUser() == null) { + return assistantResponse.error({ + body: `Authenticated user not found`, + statusCode: 401, + }); + } + } + + if (capability) { + const pluginName = getPluginNameFromRequest({ + request, + defaultPluginName: DEFAULT_PLUGIN_NAME, + }); + const registeredFeatures = context.elasticAssistant.getRegisteredFeatures(pluginName); + if (!registeredFeatures[capability]) { + return response.notFound(); + } + } + + return undefined; +}; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts new file mode 100644 index 00000000000000..dbd9d83bae3aca --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts @@ -0,0 +1,235 @@ +/* + * 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 type { AuthenticatedUser, IKibanaResponse, KibanaResponseFactory } from '@kbn/core/server'; + +import { transformError } from '@kbn/securitysolution-es-utils'; +import { + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION, + PerformKnowledgeBaseEntryBulkActionRequestBody, + API_VERSIONS, + KnowledgeBaseEntryBulkCrudActionResults, + KnowledgeBaseEntryBulkCrudActionResponse, + KnowledgeBaseEntryBulkCrudActionSummary, + PerformKnowledgeBaseEntryBulkActionResponse, +} from '@kbn/elastic-assistant-common'; +import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; + +import { performChecks } from '../../helpers'; +import { KNOWLEDGE_BASE_ENTRIES_TABLE_MAX_PAGE_SIZE } from '../../../../common/constants'; +import { EsKnowledgeBaseEntrySchema } from '../../../ai_assistant_data_clients/knowledge_base/types'; +import { ElasticAssistantPluginRouter } from '../../../types'; +import { buildResponse } from '../../utils'; +import { transformESSearchToKnowledgeBaseEntry } from '../../../ai_assistant_data_clients/knowledge_base/transforms'; +import { transformToCreateSchema } from '../../../ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry'; + +export interface BulkOperationError { + message: string; + status?: number; + document: { + id: string; + name?: string; + }; +} + +export type BulkResponse = KnowledgeBaseEntryBulkCrudActionResults & { + errors?: BulkOperationError[]; +}; + +export type BulkActionError = BulkOperationError | unknown; + +const buildBulkResponse = ( + response: KibanaResponseFactory, + { + errors = [], + updated = [], + created = [], + deleted = [], + skipped = [], + }: KnowledgeBaseEntryBulkCrudActionResults & { errors: BulkOperationError[] } +): IKibanaResponse => { + const numSucceeded = updated.length + created.length + deleted.length; + const numSkipped = skipped.length; + const numFailed = errors.length; + + const summary: KnowledgeBaseEntryBulkCrudActionSummary = { + failed: numFailed, + succeeded: numSucceeded, + skipped: numSkipped, + total: numSucceeded + numFailed + numSkipped, + }; + + const results: KnowledgeBaseEntryBulkCrudActionResults = { + updated, + created, + deleted, + skipped, + }; + + if (numFailed > 0) { + return response.custom({ + headers: { 'content-type': 'application/json' }, + body: { + message: summary.succeeded > 0 ? 'Bulk edit partially failed' : 'Bulk edit failed', + attributes: { + errors: errors.map((e: BulkOperationError) => ({ + statusCode: e.status ?? 500, + knowledgeBaseEntries: [{ id: e.document.id, name: '' }], + message: e.message, + })), + results, + summary, + }, + }, + statusCode: 500, + }); + } + + const responseBody: KnowledgeBaseEntryBulkCrudActionResponse = { + success: true, + knowledgeBaseEntriesCount: summary.total, + attributes: { results, summary }, + }; + + return response.ok({ body: responseBody }); +}; + +export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPluginRouter) => { + router.versioned + .post({ + access: 'internal', + path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION, + options: { + tags: ['access:elasticAssistant'], + timeout: { + idleSocket: moment.duration(15, 'minutes').asMilliseconds(), + }, + }, + }) + .addVersion( + { + version: API_VERSIONS.internal.v1, + validate: { + request: { + body: buildRouteValidationWithZod(PerformKnowledgeBaseEntryBulkActionRequestBody), + }, + }, + }, + async ( + context, + request, + response + ): Promise> => { + const assistantResponse = buildResponse(response); + try { + const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); + const logger = ctx.elasticAssistant.logger; + + // Perform license, authenticated user and FF checks + const checkResponse = performChecks({ + authenticatedUser: true, + capability: 'assistantKnowledgeBaseByDefault', + context: ctx, + license: true, + request, + response, + }); + if (checkResponse) { + return checkResponse; + } + + logger.debug( + `Performing bulk action on Knowledge Base Entries:\n${JSON.stringify(request.body)}` + ); + + const { body } = request; + + const operationsCount = + (body?.update ? body.update?.length : 0) + + (body?.create ? body.create?.length : 0) + + (body?.delete ? body.delete?.ids?.length ?? 0 : 0); + if (operationsCount > KNOWLEDGE_BASE_ENTRIES_TABLE_MAX_PAGE_SIZE) { + return assistantResponse.error({ + body: `More than ${KNOWLEDGE_BASE_ENTRIES_TABLE_MAX_PAGE_SIZE} ids sent for bulk edit action.`, + statusCode: 400, + }); + } + + const abortController = new AbortController(); + + // subscribing to completed$, because it handles both cases when request was completed and aborted. + // when route is finished by timeout, aborted$ is not getting fired + request.events.completed$.subscribe(() => abortController.abort()); + const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient( + false + ); + const spaceId = ctx.elasticAssistant.getSpaceId(); + // Authenticated user null check completed in `performChecks()` above + const authenticatedUser = ctx.elasticAssistant.getCurrentUser() as AuthenticatedUser; + + if (body.create && body.create.length > 0) { + const result = await kbDataClient?.findDocuments({ + perPage: 100, + page: 1, + filter: `users:{ id: "${authenticatedUser?.profile_uid}" }`, + fields: [], + }); + if (result?.data != null && result.total > 0) { + return assistantResponse.error({ + statusCode: 409, + body: `Knowledge Base Entry id's: "${transformESSearchToKnowledgeBaseEntry( + result.data + ) + .map((c) => c.id) + .join(',')}" already exists`, + }); + } + } + + const writer = await kbDataClient?.getWriter(); + const changedAt = new Date().toISOString(); + const { + errors, + docs_created: docsCreated, + docs_updated: docsUpdated, + docs_deleted: docsDeleted, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + } = await writer!.bulk({ + documentsToCreate: body.create?.map((c) => + transformToCreateSchema(changedAt, spaceId, authenticatedUser, c) + ), + documentsToDelete: body.delete?.ids, + documentsToUpdate: [], // TODO: Support bulk update + authenticatedUser, + }); + const created = + docsCreated.length > 0 + ? await kbDataClient?.findDocuments({ + page: 1, + perPage: 100, + filter: docsCreated.map((c) => `_id:${c}`).join(' OR '), + }) + : undefined; + + return buildBulkResponse(response, { + // @ts-ignore-next-line TS2322 + updated: docsUpdated, + created: created?.data ? transformESSearchToKnowledgeBaseEntry(created?.data) : [], + deleted: docsDeleted ?? [], + errors, + }); + } catch (err) { + const error = transformError(err); + return assistantResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts index 0c31974a20785f..b93ab4e894c8bb 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { IKibanaResponse } from '@kbn/core/server'; +import { IKibanaResponse } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { API_VERSIONS, @@ -15,15 +15,17 @@ import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/ import { KnowledgeBaseEntryCreateProps, KnowledgeBaseEntryResponse, + Metadata, } from '@kbn/elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen'; +import type { Document } from 'langchain/document'; import { ElasticAssistantPluginRouter } from '../../../types'; import { buildResponse } from '../../utils'; -import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../../helpers'; +import { performChecks } from '../../helpers'; export const createKnowledgeBaseEntryRoute = (router: ElasticAssistantPluginRouter): void => { router.versioned .post({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL, options: { @@ -32,7 +34,7 @@ export const createKnowledgeBaseEntryRoute = (router: ElasticAssistantPluginRout }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { body: buildRouteValidationWithZod(KnowledgeBaseEntryCreateProps), @@ -43,27 +45,40 @@ export const createKnowledgeBaseEntryRoute = (router: ElasticAssistantPluginRout const assistantResponse = buildResponse(response); try { const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); - const license = ctx.licensing.license; - if (!hasAIAssistantLicense(license)) { - return response.forbidden({ - body: { - message: UPGRADE_LICENSE_MESSAGE, - }, - }); + const logger = ctx.elasticAssistant.logger; + + // Perform license, authenticated user and FF checks + const checkResponse = performChecks({ + authenticatedUser: true, + capability: 'assistantKnowledgeBaseByDefault', + context: ctx, + license: true, + request, + response, + }); + if (checkResponse) { + return checkResponse; } - const authenticatedUser = ctx.elasticAssistant.getCurrentUser(); - if (authenticatedUser == null) { + logger.debug(`Creating KB Entry:\n${JSON.stringify(request.body)}`); + const documents: Array> = [ + { + metadata: request.body.metadata, + pageContent: request.body.text, + }, + ]; + const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient( + false + ); + const createResponse = await kbDataClient?.addKnowledgeBaseDocuments({ documents }); + + if (createResponse == null) { return assistantResponse.error({ - body: `Authenticated user not found`, - statusCode: 401, + body: `Knowledge Base Entry was not created`, + statusCode: 400, }); } - - return assistantResponse.error({ - body: `knowledge base entry was not created`, - statusCode: 400, - }); + return response.ok({ body: KnowledgeBaseEntryResponse.parse(createResponse[0]) }); } catch (err) { const error = transformError(err as Error); return assistantResponse.error({ diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts new file mode 100644 index 00000000000000..9dc7bb3f39dbf2 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.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 type { IKibanaResponse } from '@kbn/core/server'; +import { transformError } from '@kbn/securitysolution-es-utils'; + +import { + API_VERSIONS, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_FIND, + FindKnowledgeBaseEntriesRequestQuery, + FindKnowledgeBaseEntriesResponse, +} from '@kbn/elastic-assistant-common'; +import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; +import { ElasticAssistantPluginRouter } from '../../../types'; +import { buildResponse } from '../../utils'; + +import { performChecks } from '../../helpers'; +import { transformESSearchToKnowledgeBaseEntry } from '../../../ai_assistant_data_clients/knowledge_base/transforms'; +import { EsKnowledgeBaseEntrySchema } from '../../../ai_assistant_data_clients/knowledge_base/types'; + +export const findKnowledgeBaseEntriesRoute = (router: ElasticAssistantPluginRouter) => { + router.versioned + .get({ + access: 'internal', + path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_FIND, + options: { + tags: ['access:elasticAssistant'], + }, + }) + .addVersion( + { + version: API_VERSIONS.internal.v1, + validate: { + request: { + query: buildRouteValidationWithZod(FindKnowledgeBaseEntriesRequestQuery), + }, + }, + }, + async ( + context, + request, + response + ): Promise> => { + const assistantResponse = buildResponse(response); + try { + const { query } = request; + const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); + + // Perform license, authenticated user and FF checks + const checkResponse = performChecks({ + authenticatedUser: true, + capability: 'assistantKnowledgeBaseByDefault', + context: ctx, + license: true, + request, + response, + }); + if (checkResponse) { + return checkResponse; + } + + const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient( + false + ); + const currentUser = ctx.elasticAssistant.getCurrentUser(); + + const additionalFilter = query.filter ? ` AND ${query.filter}` : ''; + const result = await kbDataClient?.findDocuments({ + perPage: query.per_page, + page: query.page, + sortField: query.sort_field, + sortOrder: query.sort_order, + filter: `users:{ id: "${currentUser?.profile_uid}" }${additionalFilter}`, // TODO: Update filter to include non-user system entries + fields: query.fields, + }); + + if (result) { + return response.ok({ + body: { + perPage: result.perPage, + page: result.page, + total: result.total, + data: transformESSearchToKnowledgeBaseEntry(result.data), + }, + }); + } + return response.ok({ + body: { perPage: query.per_page, page: query.page, data: [], total: 0 }, + }); + } catch (err) { + const error = transformError(err); + return assistantResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/elastic_assistant/server/routes/register_routes.ts b/x-pack/plugins/elastic_assistant/server/routes/register_routes.ts index fc0e30f4a925c4..374b32d6cceb5d 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/register_routes.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/register_routes.ts @@ -27,6 +27,9 @@ import { bulkPromptsRoute } from './prompts/bulk_actions_route'; import { findPromptsRoute } from './prompts/find_route'; import { bulkActionAnonymizationFieldsRoute } from './anonymization_fields/bulk_actions_route'; import { findAnonymizationFieldsRoute } from './anonymization_fields/find_route'; +import { bulkActionKnowledgeBaseEntriesRoute } from './knowledge_base/entries/bulk_actions_route'; +import { createKnowledgeBaseEntryRoute } from './knowledge_base/entries/create_route'; +import { findKnowledgeBaseEntriesRoute } from './knowledge_base/entries/find_route'; export const registerRoutes = ( router: ElasticAssistantPluginRouter, @@ -49,11 +52,16 @@ export const registerRoutes = ( // User Conversations search findUserConversationsRoute(router); - // Knowledge Base + // Knowledge Base Setup deleteKnowledgeBaseRoute(router); getKnowledgeBaseStatusRoute(router, getElserId); postKnowledgeBaseRoute(router, getElserId); + // Knowledge Base Entries + findKnowledgeBaseEntriesRoute(router); + createKnowledgeBaseEntryRoute(router); + bulkActionKnowledgeBaseEntriesRoute(router); + // Actions Connector Execute (LLM Wrapper) postActionsConnectorExecuteRoute(router, getElserId); From ff19b297fb80af793919c71c2eb883406c9039c3 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 19 Jun 2024 03:00:15 +0100 Subject: [PATCH 074/123] skip flaky suite (#186438) --- .../pages/cis_integrations/cspm/cis_integration_aws.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_aws.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_aws.ts index 2dd8f36af154d8..cae23e9bfe8a42 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_aws.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_aws.ts @@ -38,7 +38,8 @@ export default function (providerContext: FtrProviderContext) { await cisIntegration.navigateToAddIntegrationCspmPage(); }); - describe('CIS_AWS Organization Cloud Formation', () => { + // FLAKY: https://github.com/elastic/kibana/issues/186438 + describe.skip('CIS_AWS Organization Cloud Formation', () => { it('Initial form state, AWS Org account, and CloudFormation should be selected by default', async () => { expect((await cisIntegration.isRadioButtonChecked('cloudbeat/cis_aws')) === true); expect((await cisIntegration.isRadioButtonChecked('organization-account')) === true); From c4cd3ab8d39da46bc4047427507eb4a5d9ad1c52 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 19 Jun 2024 03:02:16 +0100 Subject: [PATCH 075/123] skip flaky suite (#176335) --- .../user_profiles/use_bulk_get_user_profiles.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/containers/user_profiles/use_bulk_get_user_profiles.test.ts b/x-pack/plugins/cases/public/containers/user_profiles/use_bulk_get_user_profiles.test.ts index 1574c1ddd25803..5732085d99c8eb 100644 --- a/x-pack/plugins/cases/public/containers/user_profiles/use_bulk_get_user_profiles.test.ts +++ b/x-pack/plugins/cases/public/containers/user_profiles/use_bulk_get_user_profiles.test.ts @@ -19,7 +19,8 @@ jest.mock('./api'); const useKibanaMock = useKibana as jest.Mock; -describe('useBulkGetUserProfiles', () => { +// FLAKY: https://github.com/elastic/kibana/issues/176335 +describe.skip('useBulkGetUserProfiles', () => { const props = { uids: userProfilesIds, }; From 2a6172c090ba29416f01264be32d0af469c29965 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 19 Jun 2024 07:00:55 +0200 Subject: [PATCH 076/123] [api-docs] 2024-06-19 Daily api_docs build (#186441) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/742 --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- .../ai_assistant_management_selection.mdx | 2 +- api_docs/aiops.devdocs.json | 8 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.mdx | 2 +- api_docs/apm.mdx | 2 +- api_docs/apm_data_access.mdx | 2 +- api_docs/asset_manager.mdx | 2 +- api_docs/assets_data_access.mdx | 2 +- api_docs/banners.mdx | 2 +- api_docs/bfetch.mdx | 2 +- api_docs/canvas.mdx | 2 +- api_docs/cases.mdx | 2 +- api_docs/charts.mdx | 2 +- api_docs/cloud.mdx | 2 +- api_docs/cloud_data_migration.mdx | 2 +- api_docs/cloud_defend.mdx | 2 +- api_docs/cloud_experiments.mdx | 2 +- api_docs/cloud_security_posture.mdx | 2 +- api_docs/console.mdx | 2 +- api_docs/content_management.mdx | 2 +- api_docs/controls.mdx | 2 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.mdx | 4 +- api_docs/data_quality.mdx | 2 +- api_docs/data_query.mdx | 4 +- api_docs/data_search.devdocs.json | 128 + api_docs/data_search.mdx | 4 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/dataset_quality.mdx | 2 +- api_docs/deprecations_by_api.mdx | 2 +- api_docs/deprecations_by_plugin.mdx | 4 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.devdocs.json | 18 +- api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/discover_shared.mdx | 2 +- api_docs/ecs_data_quality_dashboard.mdx | 2 +- api_docs/elastic_assistant.mdx | 2 +- api_docs/embeddable.mdx | 2 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.mdx | 2 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/esql_data_grid.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_annotation_listing.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/exploratory_view.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/fields_metadata.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/files.mdx | 2 +- api_docs/files_management.mdx | 2 +- api_docs/fleet.devdocs.json | 25 +- api_docs/fleet.mdx | 4 +- api_docs/global_search.mdx | 2 +- api_docs/guided_onboarding.mdx | 2 +- api_docs/home.mdx | 2 +- api_docs/image_embeddable.mdx | 2 +- api_docs/index_lifecycle_management.mdx | 2 +- api_docs/index_management.mdx | 2 +- api_docs/infra.mdx | 2 +- api_docs/ingest_pipelines.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/integration_assistant.devdocs.json | 2417 ++++-- api_docs/integration_assistant.mdx | 11 +- api_docs/interactive_setup.mdx | 2 +- api_docs/investigate.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_actions_types.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_log_pattern_analysis.mdx | 2 +- api_docs/kbn_aiops_log_rate_analysis.mdx | 2 +- .../kbn_alerting_api_integration_helpers.mdx | 2 +- api_docs/kbn_alerting_comparators.mdx | 2 +- api_docs/kbn_alerting_state_types.mdx | 2 +- api_docs/kbn_alerting_types.mdx | 2 +- .../kbn_alerts_as_data_utils.devdocs.json | 2 +- api_docs/kbn_alerts_as_data_utils.mdx | 2 +- api_docs/kbn_alerts_ui_shared.mdx | 2 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_collection_utils.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_data_view.mdx | 2 +- api_docs/kbn_apm_synthtrace.mdx | 2 +- api_docs/kbn_apm_synthtrace_client.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_axe_config.mdx | 2 +- api_docs/kbn_bfetch_error.mdx | 2 +- api_docs/kbn_calculate_auto.mdx | 2 +- .../kbn_calculate_width_from_char_count.mdx | 2 +- api_docs/kbn_cases_components.mdx | 2 +- api_docs/kbn_cell_actions.mdx | 2 +- api_docs/kbn_chart_expressions_common.mdx | 2 +- api_docs/kbn_chart_icons.mdx | 2 +- api_docs/kbn_ci_stats_core.mdx | 2 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 2 +- api_docs/kbn_ci_stats_reporter.mdx | 2 +- api_docs/kbn_cli_dev_mode.mdx | 2 +- api_docs/kbn_code_editor.mdx | 2 +- api_docs/kbn_code_editor_mock.mdx | 2 +- api_docs/kbn_code_owners.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.devdocs.json | 7036 +++++++++++++++-- api_docs/kbn_config_schema.mdx | 4 +- ...ent_management_content_editor.devdocs.json | 2 +- .../kbn_content_management_content_editor.mdx | 2 +- ...tent_management_tabbed_table_list_view.mdx | 2 +- ...kbn_content_management_table_list_view.mdx | 2 +- ...gement_table_list_view_common.devdocs.json | 28 + ...tent_management_table_list_view_common.mdx | 4 +- ...ntent_management_table_list_view_table.mdx | 2 +- ...tent_management_user_profiles.devdocs.json | 622 ++ .../kbn_content_management_user_profiles.mdx | 33 + api_docs/kbn_content_management_utils.mdx | 2 +- .../kbn_core_analytics_browser.devdocs.json | 3186 +++++++- api_docs/kbn_core_analytics_browser.mdx | 4 +- .../kbn_core_analytics_browser_internal.mdx | 2 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 2 +- .../kbn_core_analytics_server.devdocs.json | 3197 +++++++- api_docs/kbn_core_analytics_server.mdx | 7 +- .../kbn_core_analytics_server_internal.mdx | 2 +- api_docs/kbn_core_analytics_server_mocks.mdx | 2 +- api_docs/kbn_core_application_browser.mdx | 2 +- .../kbn_core_application_browser_internal.mdx | 2 +- .../kbn_core_application_browser_mocks.mdx | 2 +- api_docs/kbn_core_application_common.mdx | 2 +- ...bn_core_apps_browser_internal.devdocs.json | 8 +- api_docs/kbn_core_apps_browser_internal.mdx | 2 +- api_docs/kbn_core_apps_browser_mocks.mdx | 2 +- api_docs/kbn_core_apps_server_internal.mdx | 2 +- api_docs/kbn_core_base_browser_mocks.mdx | 2 +- api_docs/kbn_core_base_common.mdx | 2 +- api_docs/kbn_core_base_server_internal.mdx | 2 +- api_docs/kbn_core_base_server_mocks.mdx | 2 +- .../kbn_core_capabilities_browser_mocks.mdx | 2 +- api_docs/kbn_core_capabilities_common.mdx | 2 +- api_docs/kbn_core_capabilities_server.mdx | 2 +- .../kbn_core_capabilities_server_mocks.mdx | 2 +- api_docs/kbn_core_chrome_browser.devdocs.json | 2 +- api_docs/kbn_core_chrome_browser.mdx | 2 +- api_docs/kbn_core_chrome_browser_mocks.mdx | 2 +- api_docs/kbn_core_config_server_internal.mdx | 2 +- api_docs/kbn_core_custom_branding_browser.mdx | 2 +- ..._core_custom_branding_browser_internal.mdx | 2 +- ...kbn_core_custom_branding_browser_mocks.mdx | 2 +- api_docs/kbn_core_custom_branding_common.mdx | 2 +- api_docs/kbn_core_custom_branding_server.mdx | 2 +- ...n_core_custom_branding_server_internal.mdx | 2 +- .../kbn_core_custom_branding_server_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_browser.mdx | 2 +- ...kbn_core_deprecations_browser_internal.mdx | 2 +- .../kbn_core_deprecations_browser_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_common.mdx | 2 +- api_docs/kbn_core_deprecations_server.mdx | 2 +- .../kbn_core_deprecations_server_internal.mdx | 2 +- .../kbn_core_deprecations_server_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_browser.mdx | 2 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_server.mdx | 2 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 2 +- ...e_elasticsearch_client_server_internal.mdx | 2 +- ...core_elasticsearch_client_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_server.mdx | 2 +- ...kbn_core_elasticsearch_server_internal.mdx | 2 +- .../kbn_core_elasticsearch_server_mocks.mdx | 2 +- .../kbn_core_environment_server_internal.mdx | 2 +- .../kbn_core_environment_server_mocks.mdx | 2 +- .../kbn_core_execution_context_browser.mdx | 2 +- ...ore_execution_context_browser_internal.mdx | 2 +- ...n_core_execution_context_browser_mocks.mdx | 2 +- .../kbn_core_execution_context_common.mdx | 2 +- .../kbn_core_execution_context_server.mdx | 2 +- ...core_execution_context_server_internal.mdx | 2 +- ...bn_core_execution_context_server_mocks.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser.mdx | 2 +- .../kbn_core_fatal_errors_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_browser.mdx | 2 +- api_docs/kbn_core_http_browser_internal.mdx | 2 +- api_docs/kbn_core_http_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_common.mdx | 2 +- .../kbn_core_http_context_server_mocks.mdx | 2 +- ...re_http_request_handler_context_server.mdx | 2 +- api_docs/kbn_core_http_resources_server.mdx | 2 +- ...bn_core_http_resources_server_internal.mdx | 2 +- .../kbn_core_http_resources_server_mocks.mdx | 2 +- ...e_http_router_server_internal.devdocs.json | 20 +- .../kbn_core_http_router_server_internal.mdx | 2 +- ...core_http_router_server_mocks.devdocs.json | 4 +- .../kbn_core_http_router_server_mocks.mdx | 2 +- api_docs/kbn_core_http_server.devdocs.json | 92 +- api_docs/kbn_core_http_server.mdx | 4 +- api_docs/kbn_core_http_server_internal.mdx | 2 +- api_docs/kbn_core_http_server_mocks.mdx | 2 +- api_docs/kbn_core_i18n_browser.mdx | 2 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 2 +- api_docs/kbn_core_i18n_server.mdx | 2 +- api_docs/kbn_core_i18n_server_internal.mdx | 2 +- api_docs/kbn_core_i18n_server_mocks.mdx | 2 +- ...n_core_injected_metadata_browser_mocks.mdx | 2 +- ...kbn_core_integrations_browser_internal.mdx | 2 +- .../kbn_core_integrations_browser_mocks.mdx | 2 +- .../kbn_core_lifecycle_browser.devdocs.json | 36 +- api_docs/kbn_core_lifecycle_browser.mdx | 2 +- api_docs/kbn_core_lifecycle_browser_mocks.mdx | 2 +- .../kbn_core_lifecycle_server.devdocs.json | 64 +- api_docs/kbn_core_lifecycle_server.mdx | 2 +- api_docs/kbn_core_lifecycle_server_mocks.mdx | 2 +- api_docs/kbn_core_logging_browser_mocks.mdx | 2 +- api_docs/kbn_core_logging_common_internal.mdx | 2 +- api_docs/kbn_core_logging_server.mdx | 2 +- api_docs/kbn_core_logging_server_internal.mdx | 2 +- api_docs/kbn_core_logging_server_mocks.mdx | 2 +- ...ore_metrics_collectors_server_internal.mdx | 2 +- ...n_core_metrics_collectors_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_server.mdx | 2 +- api_docs/kbn_core_metrics_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_server_mocks.mdx | 2 +- api_docs/kbn_core_mount_utils_browser.mdx | 2 +- api_docs/kbn_core_node_server.mdx | 2 +- api_docs/kbn_core_node_server_internal.mdx | 2 +- api_docs/kbn_core_node_server_mocks.mdx | 2 +- api_docs/kbn_core_notifications_browser.mdx | 2 +- ...bn_core_notifications_browser_internal.mdx | 2 +- .../kbn_core_notifications_browser_mocks.mdx | 2 +- api_docs/kbn_core_overlays_browser.mdx | 2 +- .../kbn_core_overlays_browser_internal.mdx | 2 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 2 +- api_docs/kbn_core_plugins_browser.mdx | 2 +- api_docs/kbn_core_plugins_browser_mocks.mdx | 2 +- .../kbn_core_plugins_contracts_browser.mdx | 2 +- .../kbn_core_plugins_contracts_server.mdx | 2 +- api_docs/kbn_core_plugins_server.mdx | 2 +- api_docs/kbn_core_plugins_server_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- api_docs/kbn_core_rendering_browser_mocks.mdx | 2 +- .../kbn_core_rendering_server_internal.mdx | 2 +- api_docs/kbn_core_rendering_server_mocks.mdx | 2 +- api_docs/kbn_core_root_server_internal.mdx | 2 +- .../kbn_core_saved_objects_api_browser.mdx | 2 +- .../kbn_core_saved_objects_api_server.mdx | 2 +- ...bn_core_saved_objects_api_server_mocks.mdx | 2 +- ...ore_saved_objects_base_server_internal.mdx | 2 +- ...n_core_saved_objects_base_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_browser.mdx | 2 +- ...bn_core_saved_objects_browser_internal.mdx | 2 +- .../kbn_core_saved_objects_browser_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_common.mdx | 2 +- ..._objects_import_export_server_internal.mdx | 2 +- ...ved_objects_import_export_server_mocks.mdx | 2 +- ...aved_objects_migration_server_internal.mdx | 2 +- ...e_saved_objects_migration_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_server.mdx | 2 +- ...kbn_core_saved_objects_server_internal.mdx | 2 +- .../kbn_core_saved_objects_server_mocks.mdx | 2 +- .../kbn_core_saved_objects_utils_server.mdx | 2 +- api_docs/kbn_core_security_browser.mdx | 2 +- .../kbn_core_security_browser_internal.mdx | 2 +- api_docs/kbn_core_security_browser_mocks.mdx | 2 +- api_docs/kbn_core_security_common.mdx | 2 +- api_docs/kbn_core_security_server.mdx | 2 +- .../kbn_core_security_server_internal.mdx | 2 +- api_docs/kbn_core_security_server_mocks.mdx | 2 +- api_docs/kbn_core_status_common.mdx | 2 +- api_docs/kbn_core_status_common_internal.mdx | 2 +- api_docs/kbn_core_status_server.mdx | 2 +- ...n_core_status_server_internal.devdocs.json | 28 +- api_docs/kbn_core_status_server_internal.mdx | 2 +- api_docs/kbn_core_status_server_mocks.mdx | 2 +- ...core_test_helpers_deprecations_getters.mdx | 2 +- ...n_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_test_helpers_kbn_server.mdx | 2 +- .../kbn_core_test_helpers_model_versions.mdx | 2 +- ...n_core_test_helpers_so_type_serializer.mdx | 2 +- api_docs/kbn_core_test_helpers_test_utils.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- .../kbn_core_ui_settings_browser_internal.mdx | 2 +- .../kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_core_ui_settings_server.mdx | 2 +- .../kbn_core_ui_settings_server_internal.mdx | 2 +- .../kbn_core_ui_settings_server_mocks.mdx | 2 +- api_docs/kbn_core_usage_data_server.mdx | 2 +- .../kbn_core_usage_data_server_internal.mdx | 2 +- api_docs/kbn_core_usage_data_server_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_browser.mdx | 2 +- ...kbn_core_user_profile_browser_internal.mdx | 2 +- .../kbn_core_user_profile_browser_mocks.mdx | 2 +- api_docs/kbn_core_user_profile_common.mdx | 2 +- api_docs/kbn_core_user_profile_server.mdx | 2 +- .../kbn_core_user_profile_server_internal.mdx | 2 +- .../kbn_core_user_profile_server_mocks.mdx | 2 +- api_docs/kbn_core_user_settings_server.mdx | 2 +- .../kbn_core_user_settings_server_mocks.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_custom_icons.mdx | 2 +- api_docs/kbn_custom_integrations.mdx | 2 +- api_docs/kbn_cypress_config.mdx | 2 +- api_docs/kbn_data_forge.mdx | 2 +- api_docs/kbn_data_service.mdx | 2 +- api_docs/kbn_data_stream_adapter.mdx | 2 +- api_docs/kbn_data_view_utils.devdocs.json | 69 +- api_docs/kbn_data_view_utils.mdx | 7 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_deeplinks_analytics.mdx | 2 +- api_docs/kbn_deeplinks_devtools.mdx | 2 +- api_docs/kbn_deeplinks_fleet.mdx | 2 +- api_docs/kbn_deeplinks_management.mdx | 2 +- api_docs/kbn_deeplinks_ml.mdx | 2 +- api_docs/kbn_deeplinks_observability.mdx | 2 +- api_docs/kbn_deeplinks_search.mdx | 2 +- api_docs/kbn_deeplinks_security.devdocs.json | 4 +- api_docs/kbn_deeplinks_security.mdx | 2 +- api_docs/kbn_deeplinks_shared.mdx | 2 +- api_docs/kbn_default_nav_analytics.mdx | 2 +- api_docs/kbn_default_nav_devtools.mdx | 2 +- api_docs/kbn_default_nav_management.mdx | 2 +- api_docs/kbn_default_nav_ml.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_discover_utils.devdocs.json | 96 + api_docs/kbn_discover_utils.mdx | 4 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_dom_drag_drop.mdx | 2 +- api_docs/kbn_ebt.devdocs.json | 4130 ++++++++++ api_docs/kbn_ebt.mdx | 36 + api_docs/kbn_ebt_tools.devdocs.json | 16 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_ecs_data_quality_dashboard.mdx | 2 +- api_docs/kbn_elastic_agent_utils.mdx | 2 +- api_docs/kbn_elastic_assistant.mdx | 2 +- .../kbn_elastic_assistant_common.devdocs.json | 155 +- api_docs/kbn_elastic_assistant_common.mdx | 4 +- api_docs/kbn_entities_schema.mdx | 2 +- api_docs/kbn_es.mdx | 2 +- api_docs/kbn_es_archiver.mdx | 2 +- api_docs/kbn_es_errors.mdx | 2 +- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_es_types.mdx | 2 +- api_docs/kbn_eslint_plugin_imports.mdx | 2 +- api_docs/kbn_esql_ast.devdocs.json | 14 +- api_docs/kbn_esql_ast.mdx | 4 +- api_docs/kbn_esql_utils.mdx | 2 +- ..._esql_validation_autocomplete.devdocs.json | 500 +- api_docs/kbn_esql_validation_autocomplete.mdx | 4 +- api_docs/kbn_event_annotation_common.mdx | 2 +- api_docs/kbn_event_annotation_components.mdx | 2 +- api_docs/kbn_expandable_flyout.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_field_utils.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- api_docs/kbn_formatters.mdx | 2 +- .../kbn_ftr_common_functional_services.mdx | 2 +- .../kbn_ftr_common_functional_ui_services.mdx | 2 +- api_docs/kbn_generate.mdx | 2 +- api_docs/kbn_generate_console_definitions.mdx | 2 +- api_docs/kbn_generate_csv.mdx | 2 +- api_docs/kbn_grouping.mdx | 2 +- api_docs/kbn_guided_onboarding.mdx | 2 +- api_docs/kbn_handlebars.mdx | 2 +- api_docs/kbn_hapi_mocks.mdx | 2 +- api_docs/kbn_health_gateway_server.mdx | 2 +- api_docs/kbn_home_sample_data_card.mdx | 2 +- api_docs/kbn_home_sample_data_tab.mdx | 2 +- api_docs/kbn_i18n.mdx | 2 +- api_docs/kbn_i18n_react.mdx | 2 +- api_docs/kbn_import_resolver.mdx | 2 +- api_docs/kbn_index_management.mdx | 2 +- api_docs/kbn_inference_integration_flyout.mdx | 2 +- api_docs/kbn_infra_forge.mdx | 2 +- api_docs/kbn_interpreter.mdx | 2 +- api_docs/kbn_io_ts_utils.mdx | 2 +- api_docs/kbn_ipynb.mdx | 2 +- api_docs/kbn_jest_serializers.mdx | 2 +- api_docs/kbn_journeys.mdx | 2 +- api_docs/kbn_json_ast.mdx | 2 +- api_docs/kbn_kibana_manifest_schema.mdx | 2 +- .../kbn_language_documentation_popover.mdx | 2 +- api_docs/kbn_lens_embeddable_utils.mdx | 2 +- api_docs/kbn_lens_formula_docs.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_content_badge.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_management_cards_navigation.mdx | 2 +- .../kbn_management_settings_application.mdx | 2 +- ...ent_settings_components_field_category.mdx | 2 +- ...gement_settings_components_field_input.mdx | 2 +- ...nagement_settings_components_field_row.mdx | 2 +- ...bn_management_settings_components_form.mdx | 2 +- ...n_management_settings_field_definition.mdx | 2 +- api_docs/kbn_management_settings_ids.mdx | 2 +- ...n_management_settings_section_registry.mdx | 2 +- api_docs/kbn_management_settings_types.mdx | 2 +- .../kbn_management_settings_utilities.mdx | 2 +- api_docs/kbn_management_storybook_config.mdx | 2 +- api_docs/kbn_mapbox_gl.devdocs.json | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_maps_vector_tile_utils.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_anomaly_utils.mdx | 2 +- api_docs/kbn_ml_cancellable_search.mdx | 2 +- api_docs/kbn_ml_category_validator.mdx | 2 +- api_docs/kbn_ml_chi2test.mdx | 2 +- .../kbn_ml_data_frame_analytics_utils.mdx | 2 +- api_docs/kbn_ml_data_grid.mdx | 2 +- api_docs/kbn_ml_date_picker.mdx | 2 +- api_docs/kbn_ml_date_utils.mdx | 2 +- api_docs/kbn_ml_error_utils.mdx | 2 +- api_docs/kbn_ml_in_memory_table.mdx | 2 +- api_docs/kbn_ml_is_defined.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_kibana_theme.mdx | 2 +- api_docs/kbn_ml_local_storage.mdx | 2 +- api_docs/kbn_ml_nested_property.mdx | 2 +- api_docs/kbn_ml_number_utils.mdx | 2 +- api_docs/kbn_ml_query_utils.mdx | 2 +- api_docs/kbn_ml_random_sampler_utils.mdx | 2 +- api_docs/kbn_ml_route_utils.mdx | 2 +- api_docs/kbn_ml_runtime_field_utils.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_ml_time_buckets.mdx | 2 +- api_docs/kbn_ml_trained_models_utils.mdx | 2 +- api_docs/kbn_ml_ui_actions.mdx | 2 +- api_docs/kbn_ml_url_state.mdx | 2 +- api_docs/kbn_mock_idp_utils.mdx | 2 +- api_docs/kbn_monaco.devdocs.json | 2 +- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_object_versioning.mdx | 2 +- api_docs/kbn_observability_alert_details.mdx | 2 +- .../kbn_observability_alerting_test_data.mdx | 2 +- ...ility_get_padded_alert_time_range_util.mdx | 2 +- api_docs/kbn_openapi_bundler.mdx | 2 +- api_docs/kbn_openapi_generator.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- api_docs/kbn_osquery_io_ts_types.mdx | 2 +- api_docs/kbn_panel_loader.mdx | 2 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_check.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_presentation_containers.mdx | 2 +- api_docs/kbn_presentation_publishing.mdx | 2 +- api_docs/kbn_profiling_utils.mdx | 2 +- api_docs/kbn_random_sampling.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_react_hooks.mdx | 2 +- api_docs/kbn_react_kibana_context_common.mdx | 2 +- api_docs/kbn_react_kibana_context_render.mdx | 2 +- api_docs/kbn_react_kibana_context_root.mdx | 2 +- api_docs/kbn_react_kibana_context_styled.mdx | 2 +- api_docs/kbn_react_kibana_context_theme.mdx | 2 +- api_docs/kbn_react_kibana_mount.mdx | 2 +- api_docs/kbn_repo_file_maps.mdx | 2 +- api_docs/kbn_repo_linter.mdx | 2 +- api_docs/kbn_repo_path.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_reporting_common.mdx | 2 +- api_docs/kbn_reporting_csv_share_panel.mdx | 2 +- api_docs/kbn_reporting_export_types_csv.mdx | 2 +- .../kbn_reporting_export_types_csv_common.mdx | 2 +- api_docs/kbn_reporting_export_types_pdf.mdx | 2 +- .../kbn_reporting_export_types_pdf_common.mdx | 2 +- api_docs/kbn_reporting_export_types_png.mdx | 2 +- .../kbn_reporting_export_types_png_common.mdx | 2 +- api_docs/kbn_reporting_mocks_server.mdx | 2 +- api_docs/kbn_reporting_public.mdx | 2 +- api_docs/kbn_reporting_server.mdx | 2 +- api_docs/kbn_resizable_layout.mdx | 2 +- .../kbn_response_ops_feature_flag_service.mdx | 2 +- api_docs/kbn_rison.mdx | 2 +- api_docs/kbn_router_to_openapispec.mdx | 2 +- api_docs/kbn_router_utils.mdx | 2 +- api_docs/kbn_rrule.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- api_docs/kbn_saved_objects_settings.mdx | 2 +- api_docs/kbn_search_api_panels.mdx | 2 +- api_docs/kbn_search_connectors.devdocs.json | 14 +- api_docs/kbn_search_connectors.mdx | 2 +- api_docs/kbn_search_errors.mdx | 2 +- api_docs/kbn_search_index_documents.mdx | 2 +- api_docs/kbn_search_response_warnings.mdx | 2 +- api_docs/kbn_search_types.mdx | 2 +- api_docs/kbn_security_hardening.mdx | 2 +- api_docs/kbn_security_plugin_types_common.mdx | 2 +- api_docs/kbn_security_plugin_types_public.mdx | 2 +- api_docs/kbn_security_plugin_types_server.mdx | 2 +- api_docs/kbn_security_solution_features.mdx | 2 +- api_docs/kbn_security_solution_navigation.mdx | 2 +- api_docs/kbn_security_solution_side_nav.mdx | 2 +- ...kbn_security_solution_storybook_config.mdx | 2 +- .../kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_data_table.mdx | 2 +- api_docs/kbn_securitysolution_ecs.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- ...ritysolution_exception_list_components.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ..._securitysolution_io_ts_alerting_types.mdx | 2 +- .../kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- .../kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- api_docs/kbn_serverless_common_settings.mdx | 2 +- .../kbn_serverless_observability_settings.mdx | 2 +- api_docs/kbn_serverless_project_switcher.mdx | 2 +- api_docs/kbn_serverless_search_settings.mdx | 2 +- api_docs/kbn_serverless_security_settings.mdx | 2 +- api_docs/kbn_serverless_storybook_config.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- api_docs/kbn_shared_ux_avatar_solution.mdx | 2 +- .../kbn_shared_ux_button_exit_full_screen.mdx | 2 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_chrome_navigation.mdx | 2 +- api_docs/kbn_shared_ux_error_boundary.mdx | 2 +- api_docs/kbn_shared_ux_file_context.mdx | 2 +- api_docs/kbn_shared_ux_file_image.mdx | 2 +- api_docs/kbn_shared_ux_file_image_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_mocks.mdx | 2 +- api_docs/kbn_shared_ux_file_picker.mdx | 2 +- api_docs/kbn_shared_ux_file_types.mdx | 2 +- api_docs/kbn_shared_ux_file_upload.mdx | 2 +- api_docs/kbn_shared_ux_file_util.mdx | 2 +- api_docs/kbn_shared_ux_link_redirect_app.mdx | 2 +- .../kbn_shared_ux_link_redirect_app_mocks.mdx | 2 +- api_docs/kbn_shared_ux_markdown.mdx | 2 +- api_docs/kbn_shared_ux_markdown_mocks.mdx | 2 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 2 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 2 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_template.mdx | 2 +- ...n_shared_ux_page_kibana_template_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data.mdx | 2 +- .../kbn_shared_ux_page_no_data_config.mdx | 2 +- ...bn_shared_ux_page_no_data_config_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_prompt_not_found.mdx | 2 +- api_docs/kbn_shared_ux_router.mdx | 2 +- api_docs/kbn_shared_ux_router_mocks.mdx | 2 +- api_docs/kbn_shared_ux_storybook_config.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_tabbed_modal.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_slo_schema.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_sort_predicates.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.mdx | 2 +- api_docs/kbn_test_eui_helpers.mdx | 2 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_test_subj_selector.mdx | 2 +- api_docs/kbn_text_based_editor.mdx | 2 +- api_docs/kbn_timerange.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_triggers_actions_ui_types.mdx | 2 +- api_docs/kbn_try_in_console.mdx | 2 +- api_docs/kbn_ts_projects.mdx | 2 +- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kbn_ui_actions_browser.mdx | 2 +- api_docs/kbn_ui_shared_deps_src.devdocs.json | 11 - api_docs/kbn_ui_shared_deps_src.mdx | 4 +- api_docs/kbn_ui_theme.devdocs.json | 12 - api_docs/kbn_ui_theme.mdx | 2 +- api_docs/kbn_unified_data_table.mdx | 2 +- api_docs/kbn_unified_doc_viewer.mdx | 2 +- api_docs/kbn_unified_field_list.mdx | 2 +- api_docs/kbn_unsaved_changes_badge.mdx | 2 +- api_docs/kbn_unsaved_changes_prompt.mdx | 2 +- api_docs/kbn_use_tracked_promise.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_visualization_ui_components.mdx | 2 +- api_docs/kbn_visualization_utils.mdx | 2 +- api_docs/kbn_xstate_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kbn_zod_helpers.devdocs.json | 43 + api_docs/kbn_zod_helpers.mdx | 4 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.mdx | 2 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/links.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/logs_data_access.mdx | 2 +- api_docs/logs_explorer.mdx | 2 +- api_docs/logs_shared.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/metrics_data_access.mdx | 2 +- api_docs/ml.mdx | 2 +- api_docs/mock_idp_plugin.mdx | 2 +- api_docs/monitoring.mdx | 2 +- api_docs/monitoring_collection.mdx | 2 +- api_docs/navigation.mdx | 2 +- api_docs/newsfeed.mdx | 2 +- api_docs/no_data_page.mdx | 2 +- api_docs/notifications.mdx | 2 +- api_docs/observability.devdocs.json | 4 +- api_docs/observability.mdx | 2 +- api_docs/observability_a_i_assistant.mdx | 2 +- api_docs/observability_a_i_assistant_app.mdx | 2 +- .../observability_ai_assistant_management.mdx | 2 +- api_docs/observability_logs_explorer.mdx | 2 +- api_docs/observability_onboarding.mdx | 2 +- api_docs/observability_shared.mdx | 2 +- api_docs/osquery.mdx | 2 +- api_docs/painless_lab.mdx | 2 +- api_docs/plugin_directory.mdx | 43 +- api_docs/presentation_panel.mdx | 2 +- api_docs/presentation_util.mdx | 2 +- api_docs/profiling.mdx | 2 +- api_docs/profiling_data_access.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_finder.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/saved_search.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/search_connectors.mdx | 2 +- api_docs/search_inference_endpoints.mdx | 2 +- api_docs/search_notebooks.mdx | 2 +- api_docs/search_playground.mdx | 2 +- api_docs/security.mdx | 2 +- api_docs/security_solution.devdocs.json | 12 +- api_docs/security_solution.mdx | 2 +- api_docs/security_solution_ess.mdx | 2 +- api_docs/security_solution_serverless.mdx | 2 +- api_docs/serverless.mdx | 2 +- api_docs/serverless_observability.mdx | 2 +- api_docs/serverless_search.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.mdx | 2 +- api_docs/slo.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.devdocs.json | 37 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/stack_connectors.devdocs.json | 2 +- api_docs/stack_connectors.mdx | 2 +- api_docs/task_manager.mdx | 2 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/text_based_languages.mdx | 2 +- api_docs/threat_intelligence.mdx | 2 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_doc_viewer.mdx | 2 +- api_docs/unified_histogram.mdx | 2 +- api_docs/unified_search.devdocs.json | 8 +- api_docs/unified_search.mdx | 2 +- api_docs/unified_search_autocomplete.mdx | 2 +- api_docs/uptime.mdx | 2 +- api_docs/url_forwarding.mdx | 2 +- api_docs/usage_collection.devdocs.json | 2 +- api_docs/usage_collection.mdx | 2 +- api_docs/ux.mdx | 2 +- api_docs/vis_default_editor.mdx | 2 +- api_docs/vis_type_gauge.mdx | 2 +- api_docs/vis_type_heatmap.mdx | 2 +- api_docs/vis_type_pie.mdx | 2 +- api_docs/vis_type_table.mdx | 2 +- api_docs/vis_type_timelion.mdx | 2 +- api_docs/vis_type_timeseries.mdx | 2 +- api_docs/vis_type_vega.mdx | 2 +- api_docs/vis_type_vislib.mdx | 2 +- api_docs/vis_type_xy.mdx | 2 +- api_docs/visualizations.mdx | 2 +- 736 files changed, 20759 insertions(+), 2844 deletions(-) create mode 100644 api_docs/kbn_content_management_user_profiles.devdocs.json create mode 100644 api_docs/kbn_content_management_user_profiles.mdx create mode 100644 api_docs/kbn_ebt.devdocs.json create mode 100644 api_docs/kbn_ebt.mdx diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 624022104e4b52..246481da117667 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 779596da4321e7..467d9cf5a7b1f9 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/ai_assistant_management_selection.mdx b/api_docs/ai_assistant_management_selection.mdx index 48d70e70a59824..e2ebb27cfb3f10 100644 --- a/api_docs/ai_assistant_management_selection.mdx +++ b/api_docs/ai_assistant_management_selection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiAssistantManagementSelection title: "aiAssistantManagementSelection" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementSelection plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; diff --git a/api_docs/aiops.devdocs.json b/api_docs/aiops.devdocs.json index 0f81782c4ed41c..5d8cd183f74165 100644 --- a/api_docs/aiops.devdocs.json +++ b/api_docs/aiops.devdocs.json @@ -242,9 +242,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -252,9 +252,9 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 6589c58e343975..f5e85bf416a3c4 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index a158e8daac03af..174daf92bb3021 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index aa4431dbb04dad..d9ccc16a8acb4f 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index 3e2cc9fefafc04..cf0bc62f7d9857 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index 2d1ba34fc9aaa8..64cfd25389da01 100644 --- a/api_docs/asset_manager.mdx +++ b/api_docs/asset_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetManager title: "assetManager" image: https://source.unsplash.com/400x175/?github description: API docs for the assetManager plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetManager'] --- import assetManagerObj from './asset_manager.devdocs.json'; diff --git a/api_docs/assets_data_access.mdx b/api_docs/assets_data_access.mdx index 3ee0d44d975bd4..76dad9651578f9 100644 --- a/api_docs/assets_data_access.mdx +++ b/api_docs/assets_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetsDataAccess title: "assetsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the assetsDataAccess plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetsDataAccess'] --- import assetsDataAccessObj from './assets_data_access.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index fb0a9a20e575cc..4c8b9bbe192512 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 393d71d9328ced..7d4dd4fd3ca997 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index 7c71ac4bfb55e1..91e867a7999af0 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index c29e6f64f1930a..2beb8d47c69308 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index ca4066e185d276..7f1e24b9fea6d6 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index b1e7c01136a03e..190013ec6c9cfe 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index 69ff8dc302a537..bb3b69a7c63f12 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index 79bf2006480fd9..2d88f69aeec5cc 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index e540ca3c9d751a..daf262ab941382 100644 --- a/api_docs/cloud_experiments.mdx +++ b/api_docs/cloud_experiments.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudExperiments title: "cloudExperiments" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudExperiments plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudExperiments'] --- import cloudExperimentsObj from './cloud_experiments.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 307768caee6aa5..a812d76502208f 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index 31535c63a5280b..8b056c595d8d85 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index 51ec36c9a0e939..a061227fb6cae2 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 61fad6567819c5..97ce8812891425 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 55e65c72384d83..aef3f276d8a1c3 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index dd62d55494171b..96515a7692a6c6 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index d2b741e32aed65..119f9b57bf1722 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index b8bd937dbe6c22..4bc38d07ab1b54 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3194 | 31 | 2585 | 24 | +| 3199 | 31 | 2590 | 24 | ## Client diff --git a/api_docs/data_quality.mdx b/api_docs/data_quality.mdx index 4d138efed58aea..c9508d873d3ce5 100644 --- a/api_docs/data_quality.mdx +++ b/api_docs/data_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataQuality title: "dataQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the dataQuality plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataQuality'] --- import dataQualityObj from './data_quality.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index ff7b36e4871757..3123c6516428ad 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3194 | 31 | 2585 | 24 | +| 3199 | 31 | 2590 | 24 | ## Client diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index a9e4a675758c1c..3e3047831b93f7 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -16864,6 +16864,134 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.queryToFields", + "type": "Function", + "tags": [], + "label": "queryToFields", + "description": [], + "signature": [ + "({\n dataView,\n sort,\n request,\n}: { dataView: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewLazy", + "text": "DataViewLazy" + }, + "; sort?: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.EsQuerySortValue", + "text": "EsQuerySortValue" + }, + " | ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.EsQuerySortValue", + "text": "EsQuerySortValue" + }, + "[] | undefined; request: ", + "SearchRequest", + "; }) => Promise>" + ], + "path": "src/plugins/data/common/search/search_source/query_to_fields.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.queryToFields.$1", + "type": "Object", + "tags": [], + "label": "{\n dataView,\n sort,\n request,\n}", + "description": [], + "path": "src/plugins/data/common/search/search_source/query_to_fields.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.queryToFields.$1.dataView", + "type": "Object", + "tags": [], + "label": "dataView", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewLazy", + "text": "DataViewLazy" + } + ], + "path": "src/plugins/data/common/search/search_source/query_to_fields.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.queryToFields.$1.sort", + "type": "CompoundType", + "tags": [], + "label": "sort", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.EsQuerySortValue", + "text": "EsQuerySortValue" + }, + " | ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.EsQuerySortValue", + "text": "EsQuerySortValue" + }, + "[] | undefined" + ], + "path": "src/plugins/data/common/search/search_source/query_to_fields.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.queryToFields.$1.request", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + "{ [x: string]: any; }" + ], + "path": "src/plugins/data/common/search/search_source/query_to_fields.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.splitStringInterval", diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 066c7271b7b527..181a37757cacb4 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3194 | 31 | 2585 | 24 | +| 3199 | 31 | 2590 | 24 | ## Client diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 296636689811ff..3af5d0fe9268ab 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 94ebc7428bc257..206f19c4001226 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 4cc110a02ed312..b7a04fc6457ca3 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 23caaad9e7d54a..74c481eaad31cc 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index f30163d4e24d12..d432893bc384f2 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 7f3ddaf93dd5e3..9be5bb8dcf9604 100644 --- a/api_docs/dataset_quality.mdx +++ b/api_docs/dataset_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/datasetQuality title: "datasetQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the datasetQuality plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'datasetQuality'] --- import datasetQualityObj from './dataset_quality.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index c810331094fbbd..5c6f96d6421d7b 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 7f17da6336fadc..4752ee8c2b5413 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -360,7 +360,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [esql_theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/esql_theme.ts#:~:text=darkMode), [esql_theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/esql_theme.ts#:~:text=darkMode), [esql_theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/esql_theme.ts#:~:text=darkMode), [esql_theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/esql_theme.ts#:~:text=darkMode), [esql_theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/esql_theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode) | - | +| | [esql_theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/esql_theme.ts#:~:text=darkMode), [esql_theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/esql/lib/esql_theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode), [theme.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-monaco/src/console/theme.ts#:~:text=darkMode) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 73a33c4668a804..c99f47c97e3527 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 953a9839ff37a9..35498a89f5b17a 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.devdocs.json b/api_docs/discover.devdocs.json index 1e2946e6fa7806..26f8c41e05c837 100644 --- a/api_docs/discover.devdocs.json +++ b/api_docs/discover.devdocs.json @@ -1707,7 +1707,7 @@ "tags": [], "label": "DiscoverSetup", "description": [], - "path": "src/plugins/discover/public/plugin.tsx", + "path": "src/plugins/discover/public/types.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1730,7 +1730,7 @@ }, " | undefined" ], - "path": "src/plugins/discover/public/plugin.tsx", + "path": "src/plugins/discover/public/types.ts", "deprecated": false, "trackAdoption": false }, @@ -1744,7 +1744,7 @@ "signature": [ "() => void" ], - "path": "src/plugins/discover/public/plugin.tsx", + "path": "src/plugins/discover/public/types.ts", "deprecated": false, "trackAdoption": false, "children": [], @@ -1760,7 +1760,7 @@ "signature": [ "(projectNavId: string, options: { enabled: boolean; showLogsExplorerTabs: boolean; }) => void" ], - "path": "src/plugins/discover/public/plugin.tsx", + "path": "src/plugins/discover/public/types.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1774,7 +1774,7 @@ "signature": [ "string" ], - "path": "src/plugins/discover/public/plugin.tsx", + "path": "src/plugins/discover/public/types.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -1789,7 +1789,7 @@ "signature": [ "{ enabled: boolean; showLogsExplorerTabs: boolean; }" ], - "path": "src/plugins/discover/public/plugin.tsx", + "path": "src/plugins/discover/public/types.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -1808,7 +1808,7 @@ "tags": [], "label": "DiscoverStart", "description": [], - "path": "src/plugins/discover/public/plugin.tsx", + "path": "src/plugins/discover/public/types.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1831,7 +1831,7 @@ }, " | undefined" ], - "path": "src/plugins/discover/public/plugin.tsx", + "path": "src/plugins/discover/public/types.ts", "deprecated": false, "trackAdoption": false }, @@ -1861,7 +1861,7 @@ }, ">" ], - "path": "src/plugins/discover/public/plugin.tsx", + "path": "src/plugins/discover/public/types.ts", "deprecated": false, "trackAdoption": false } diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index e364ccc82a307a..64e53552a24f31 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index c77515d70677e4..5583e7fac0809a 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/discover_shared.mdx b/api_docs/discover_shared.mdx index 915e355fd79e4b..00441fc0a8e038 100644 --- a/api_docs/discover_shared.mdx +++ b/api_docs/discover_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverShared title: "discoverShared" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverShared plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverShared'] --- import discoverSharedObj from './discover_shared.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index 1a6f9e9575cd94..04dbf12c647527 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index 441403cde90671..2d685a960e6ccb 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 76871e6e680839..6a9cebf1365b00 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index e04871b3b1db93..345548c4b57bff 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index 8d9ac944789712..e9373181cd163b 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index 1f3003a64cb9b3..c9eee95cb72b9c 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 8108a8b6776ee1..e831609643e153 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/esql_data_grid.mdx b/api_docs/esql_data_grid.mdx index 529e5bfc24b8cf..bd96bca5d8a5e3 100644 --- a/api_docs/esql_data_grid.mdx +++ b/api_docs/esql_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esqlDataGrid title: "esqlDataGrid" image: https://source.unsplash.com/400x175/?github description: API docs for the esqlDataGrid plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esqlDataGrid'] --- import esqlDataGridObj from './esql_data_grid.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 1c9e14ba90492c..0f7fd892c5e5cc 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index d45db1f6914e6b..025991c1fda515 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index da36e99e65ca2d..f1ae9dc895fd49 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/exploratory_view.mdx b/api_docs/exploratory_view.mdx index 0025d08edc1711..81c45d0084cff5 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'exploratoryView'] --- import exploratoryViewObj from './exploratory_view.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 01eafa01dee305..6359145989bed1 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 925852e77d69b7..88e7721ea46a38 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index 8aa5f4462cf5f3..ce962310cffe1f 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index bba400d1b3045f..0dbd83678d8133 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index 1a303f42e9638c..f4b89b2c1e8fb7 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index 0ffcf4d1ee5bd9..13f027fff7e226 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index 305b36fdb62077..f86f46f96ef8a0 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index 0cbea72f7563c6..b13293aeedd00a 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index c35b81f9083150..06fbe7aea3fe62 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index 78a57072b2ae29..896a29a9180edc 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index 3fa4ac3f62b0f1..5f99e621e14233 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index 4452aa394f13c1..b81f4fdee7ec19 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index 626bd0655b3dc1..0eae0e2e002e7f 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index ad99535b03f13e..0427130b0f0bf8 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index a319f1537ccf52..bc5f7857bcc3c3 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index bb88bdc3705a7d..8a1e28a04bf08e 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/fields_metadata.mdx b/api_docs/fields_metadata.mdx index ce996ad370aa52..4216234eb614b9 100644 --- a/api_docs/fields_metadata.mdx +++ b/api_docs/fields_metadata.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldsMetadata title: "fieldsMetadata" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldsMetadata plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldsMetadata'] --- import fieldsMetadataObj from './fields_metadata.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 790b8fc5cff155..260ec379684246 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index a2fd13d1c99648..b652e97a9a80c9 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index 5147aec2df8abc..a557fd5e66e8ae 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index eccb9aef35f1bc..9106288513ae1d 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -6349,7 +6349,7 @@ "section": "def-common.SavedObjectsClientContract", "text": "SavedObjectsClientContract" }, - ", ids: string[], options?: { fields?: string[] | undefined; withPackagePolicies?: boolean | undefined; ignoreMissing?: boolean | undefined; }) => Promise<", + ", ids: (string | { id: string; spaceId?: string | undefined; })[], options?: { fields?: string[] | undefined; withPackagePolicies?: boolean | undefined; ignoreMissing?: boolean | undefined; }) => Promise<", { "pluginId": "fleet", "scope": "common", @@ -6392,7 +6392,7 @@ "label": "ids", "description": [], "signature": [ - "string[]" + "(string | { id: string; spaceId?: string | undefined; })[]" ], "path": "x-pack/plugins/fleet/server/services/agent_policy.ts", "deprecated": false, @@ -9915,7 +9915,7 @@ "section": "def-common.ListWithKuery", "text": "ListWithKuery" }, - ") => Promise<", + " & { spaceId?: string | undefined; }) => Promise<", { "pluginId": "fleet", "scope": "common", @@ -9961,7 +9961,7 @@ { "parentPluginId": "fleet", "id": "def-server.PackagePolicyClient.list.$2", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "options", "description": [], @@ -9972,7 +9972,8 @@ "docId": "kibFleetPluginApi", "section": "def-common.ListWithKuery", "text": "ListWithKuery" - } + }, + " & { spaceId?: string | undefined; }" ], "path": "x-pack/plugins/fleet/server/services/package_policy_service.ts", "deprecated": false, @@ -23986,6 +23987,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "fleet", + "id": "def-common.PackagePolicy.spaceId", + "type": "string", + "tags": [], + "label": "spaceId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "fleet", "id": "def-common.PackagePolicy.inputs", diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 75c84f6c1d72ba..3730f61af825ba 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1338 | 5 | 1216 | 72 | +| 1339 | 5 | 1217 | 72 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 215446f0c0bb3d..627f17964ac926 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index a86418e1b03d69..0a2c709cc164a6 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index d08cb4c662cf90..899804f8cf78e2 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index 1025665cd37ed3..7557dc60759772 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index 03bb198df26a7e..a4fc0e4c26f989 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 1942fce8dc4b34..cf7e4b6bd480ac 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index adf5bec595e959..911075f5d65a29 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/ingest_pipelines.mdx b/api_docs/ingest_pipelines.mdx index fbf0e38e34f545..4a0a9592144b92 100644 --- a/api_docs/ingest_pipelines.mdx +++ b/api_docs/ingest_pipelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ingestPipelines title: "ingestPipelines" image: https://source.unsplash.com/400x175/?github description: API docs for the ingestPipelines plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ingestPipelines'] --- import ingestPipelinesObj from './ingest_pipelines.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 14af91942d5bb7..ebe749551fc4d2 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/integration_assistant.devdocs.json b/api_docs/integration_assistant.devdocs.json index d5c5221c93afa9..94182a303ea0f3 100644 --- a/api_docs/integration_assistant.devdocs.json +++ b/api_docs/integration_assistant.devdocs.json @@ -47,873 +47,316 @@ "common": { "classes": [], "functions": [], - "interfaces": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.BuildIntegrationApiRequest", - "type": "Interface", - "tags": [], - "label": "BuildIntegrationApiRequest", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.BuildIntegrationApiRequest.integration", - "type": "Object", - "tags": [], - "label": "integration", - "description": [], - "signature": [ - { - "pluginId": "integrationAssistant", - "scope": "common", - "docId": "kibIntegrationAssistantPluginApi", - "section": "def-common.Integration", - "text": "Integration" - } - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, + "interfaces": [], + "enums": [], + "misc": [ { "parentPluginId": "integrationAssistant", - "id": "def-common.CategorizationApiRequest", - "type": "Interface", + "id": "def-common.BuildIntegrationRequestBody", + "type": "Type", "tags": [], - "label": "CategorizationApiRequest", + "label": "BuildIntegrationRequestBody", "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.CategorizationApiRequest.packageName", - "type": "string", - "tags": [], - "label": "packageName", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, + "signature": [ + "{ integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { - "parentPluginId": "integrationAssistant", - "id": "def-common.CategorizationApiRequest.dataStreamName", - "type": "string", - "tags": [], - "label": "dataStreamName", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", { - "parentPluginId": "integrationAssistant", - "id": "def-common.CategorizationApiRequest.rawSamples", - "type": "Array", - "tags": [], - "label": "rawSamples", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.CategorizationApiRequest.currentPipeline", - "type": "Uncategorized", - "tags": [], - "label": "currentPipeline", - "description": [], - "signature": [ - "object" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } + "[] | undefined; }; docs: {}[]; }[]; logo?: string | undefined; }; }" ], + "path": "x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.ts", + "deprecated": false, + "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.CategorizationApiResponse", - "type": "Interface", + "id": "def-common.CATEGORIZATION_GRAPH_PATH", + "type": "string", "tags": [], - "label": "CategorizationApiResponse", + "label": "CATEGORIZATION_GRAPH_PATH", "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", + "path": "x-pack/plugins/integration_assistant/common/constants.ts", "deprecated": false, "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.CategorizationApiResponse.results", - "type": "Object", - "tags": [], - "label": "results", - "description": [], - "signature": [ - "{ pipeline: object; docs: object[]; }" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.DataStream", - "type": "Interface", + "id": "def-common.CategorizationRequestBody", + "type": "Type", "tags": [], - "label": "DataStream", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.DataStream.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.DataStream.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.DataStream.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.DataStream.inputTypes", - "type": "Array", - "tags": [], - "label": "inputTypes", - "description": [], - "signature": [ - { - "pluginId": "integrationAssistant", - "scope": "common", - "docId": "kibIntegrationAssistantPluginApi", - "section": "def-common.InputTypes", - "text": "InputTypes" - }, - "[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.DataStream.rawSamples", - "type": "Array", - "tags": [], - "label": "rawSamples", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.DataStream.pipeline", - "type": "Uncategorized", - "tags": [], - "label": "pipeline", - "description": [], - "signature": [ - "object" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.DataStream.docs", - "type": "Array", - "tags": [], - "label": "docs", - "description": [], - "signature": [ - "object[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.EcsMappingApiRequest", - "type": "Interface", - "tags": [], - "label": "EcsMappingApiRequest", + "label": "CategorizationRequestBody", "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.EcsMappingApiRequest.packageName", - "type": "string", - "tags": [], - "label": "packageName", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, + "signature": [ + "{ connectorId: string; packageName: string; rawSamples: string[]; datastreamName: string; currentPipeline: { processors: ", { - "parentPluginId": "integrationAssistant", - "id": "def-common.EcsMappingApiRequest.dataStreamName", - "type": "string", - "tags": [], - "label": "dataStreamName", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", { - "parentPluginId": "integrationAssistant", - "id": "def-common.EcsMappingApiRequest.rawSamples", - "type": "Array", - "tags": [], - "label": "rawSamples", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.EcsMappingApiRequest.mapping", - "type": "Uncategorized", - "tags": [], - "label": "mapping", - "description": [], - "signature": [ - "object | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } + "[] | undefined; }; }" ], - "initialIsOpen": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.EcsMappingApiResponse", - "type": "Interface", - "tags": [], - "label": "EcsMappingApiResponse", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", + "path": "x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.ts", "deprecated": false, "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.EcsMappingApiResponse.results", - "type": "Object", - "tags": [], - "label": "results", - "description": [], - "signature": [ - "{ mapping: object; pipeline: object; }" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.ESProcessorItem", - "type": "Interface", + "id": "def-common.CategorizationResponse", + "type": "Type", "tags": [], - "label": "ESProcessorItem", + "label": "CategorizationResponse", "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "signature": [ + "{ results: { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", { - "parentPluginId": "integrationAssistant", - "id": "def-common.ESProcessorItem.Unnamed", - "type": "IndexSignature", - "tags": [], - "label": "[processorName: string]: ESProcessorOptions", - "description": [], - "signature": [ - "[processorName: string]: ", - { - "pluginId": "integrationAssistant", - "scope": "common", - "docId": "kibIntegrationAssistantPluginApi", - "section": "def-common.ESProcessorOptions", - "text": "ESProcessorOptions" - } - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }; }" ], + "path": "x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.ts", + "deprecated": false, + "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.ESProcessorOptions", - "type": "Interface", + "id": "def-common.CheckPipelineRequestBody", + "type": "Type", "tags": [], - "label": "ESProcessorOptions", + "label": "CheckPipelineRequestBody", "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.ESProcessorOptions.on_failure", - "type": "Array", - "tags": [], - "label": "on_failure", - "description": [], - "signature": [ - { - "pluginId": "integrationAssistant", - "scope": "common", - "docId": "kibIntegrationAssistantPluginApi", - "section": "def-common.ESProcessorItem", - "text": "ESProcessorItem" - }, - "[] | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.ESProcessorOptions.ignore_failure", - "type": "CompoundType", - "tags": [], - "label": "ignore_failure", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.ESProcessorOptions.ignore_missing", - "type": "CompoundType", - "tags": [], - "label": "ignore_missing", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.ESProcessorOptions.if", - "type": "string", - "tags": [], - "label": "if", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.ESProcessorOptions.tag", - "type": "string", - "tags": [], - "label": "tag", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.ESProcessorOptions.Unnamed", - "type": "IndexSignature", - "tags": [], - "label": "[key: string]: unknown", - "description": [], - "signature": [ - "[key: string]: unknown" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } + "signature": [ + "{ rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; }" ], + "path": "x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.ts", + "deprecated": false, + "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.Integration", - "type": "Interface", + "id": "def-common.CheckPipelineResponse", + "type": "Type", "tags": [], - "label": "Integration", + "label": "CheckPipelineResponse", "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Integration.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Integration.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Integration.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Integration.dataStreams", - "type": "Array", - "tags": [], - "label": "dataStreams", - "description": [], - "signature": [ - { - "pluginId": "integrationAssistant", - "scope": "common", - "docId": "kibIntegrationAssistantPluginApi", - "section": "def-common.DataStream", - "text": "DataStream" - }, - "[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Integration.logo", - "type": "string", - "tags": [], - "label": "logo", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } + "signature": [ + "{ pipelineResults: {}[]; errors?: {}[] | undefined; }" ], + "path": "x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.ts", + "deprecated": false, + "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.Pipeline", - "type": "Interface", + "id": "def-common.Datastream", + "type": "Type", "tags": [], - "label": "Pipeline", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Pipeline.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Pipeline.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Pipeline.version", - "type": "number", - "tags": [], - "label": "version", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Pipeline.processors", - "type": "Array", - "tags": [], - "label": "processors", - "description": [], - "signature": [ - { - "pluginId": "integrationAssistant", - "scope": "common", - "docId": "kibIntegrationAssistantPluginApi", - "section": "def-common.ESProcessorItem", - "text": "ESProcessorItem" - }, - "[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.Pipeline.on_failure", - "type": "Array", - "tags": [], - "label": "on_failure", - "description": [], - "signature": [ - { - "pluginId": "integrationAssistant", - "scope": "common", - "docId": "kibIntegrationAssistantPluginApi", - "section": "def-common.ESProcessorItem", - "text": "ESProcessorItem" - }, - "[] | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.RelatedApiRequest", - "type": "Interface", - "tags": [], - "label": "RelatedApiRequest", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.RelatedApiRequest.packageName", - "type": "string", - "tags": [], - "label": "packageName", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, + "label": "Datastream", + "description": [ + "\nThe datastream object." + ], + "signature": [ + "{ name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { - "parentPluginId": "integrationAssistant", - "id": "def-common.RelatedApiRequest.dataStreamName", - "type": "string", - "tags": [], - "label": "dataStreamName", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", { - "parentPluginId": "integrationAssistant", - "id": "def-common.RelatedApiRequest.rawSamples", - "type": "Array", - "tags": [], - "label": "rawSamples", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.RelatedApiRequest.currentPipeline", - "type": "Uncategorized", - "tags": [], - "label": "currentPipeline", - "description": [], - "signature": [ - "object" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } + "[] | undefined; }; docs: {}[]; }" ], + "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts", + "deprecated": false, + "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.RelatedApiResponse", - "type": "Interface", + "id": "def-common.ECS_GRAPH_PATH", + "type": "string", "tags": [], - "label": "RelatedApiResponse", + "label": "ECS_GRAPH_PATH", "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", + "path": "x-pack/plugins/integration_assistant/common/constants.ts", "deprecated": false, "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.RelatedApiResponse.results", - "type": "Object", - "tags": [], - "label": "results", - "description": [], - "signature": [ - "{ pipeline: object; docs: object[]; }" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.TestPipelineApiRequest", - "type": "Interface", + "id": "def-common.EcsMappingRequestBody", + "type": "Type", "tags": [], - "label": "TestPipelineApiRequest", + "label": "EcsMappingRequestBody", "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", + "signature": [ + "{ connectorId: string; packageName: string; rawSamples: string[]; datastreamName: string; mapping?: {} | undefined; }" + ], + "path": "x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.ts", "deprecated": false, "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.TestPipelineApiRequest.rawSamples", - "type": "Array", - "tags": [], - "label": "rawSamples", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.TestPipelineApiRequest.currentPipeline", - "type": "Object", - "tags": [], - "label": "currentPipeline", - "description": [], - "signature": [ - { - "pluginId": "integrationAssistant", - "scope": "common", - "docId": "kibIntegrationAssistantPluginApi", - "section": "def-common.Pipeline", - "text": "Pipeline" - } - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.TestPipelineApiResponse", - "type": "Interface", + "id": "def-common.EcsMappingResponse", + "type": "Type", "tags": [], - "label": "TestPipelineApiResponse", + "label": "EcsMappingResponse", "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "integrationAssistant", - "id": "def-common.TestPipelineApiResponse.pipelineResults", - "type": "Array", - "tags": [], - "label": "pipelineResults", - "description": [], - "signature": [ - "object[]" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "integrationAssistant", - "id": "def-common.TestPipelineApiResponse.errors", - "type": "Array", - "tags": [], - "label": "errors", - "description": [], - "signature": [ - "object[] | undefined" - ], - "path": "x-pack/plugins/integration_assistant/common/types.ts", - "deprecated": false, - "trackAdoption": false - } + "signature": [ + "{ results: { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; mapping: {}; }; }" ], + "path": "x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.ts", + "deprecated": false, + "trackAdoption": false, "initialIsOpen": false - } - ], - "enums": [ + }, { "parentPluginId": "integrationAssistant", - "id": "def-common.InputTypes", - "type": "Enum", + "id": "def-common.ESProcessorItem", + "type": "Type", "tags": [], - "label": "InputTypes", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/types.ts", + "label": "ESProcessorItem", + "description": [ + "\nProcessor item for the Elasticsearch processor." + ], + "signature": [ + "{ [x: string]: ", + "ESProcessorOptions", + "; }" + ], + "path": "x-pack/plugins/integration_assistant/common/api/model/processor_attributes.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false - } - ], - "misc": [ + }, { "parentPluginId": "integrationAssistant", - "id": "def-common.CATEGORIZATION_GRAPH_PATH", - "type": "string", + "id": "def-common.InputType", + "type": "Type", "tags": [], - "label": "CATEGORIZATION_GRAPH_PATH", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/constants.ts", + "label": "InputType", + "description": [ + "\nThe input type for the datastream to pull logs from." + ], + "signature": [ + "\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\"" + ], + "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "integrationAssistant", - "id": "def-common.ECS_GRAPH_PATH", - "type": "string", + "id": "def-common.Integration", + "type": "Type", "tags": [], - "label": "ECS_GRAPH_PATH", - "description": [], - "path": "x-pack/plugins/integration_assistant/common/constants.ts", + "label": "Integration", + "description": [ + "\nThe integration object." + ], + "signature": [ + "{ name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }[]; logo?: string | undefined; }" + ], + "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -960,6 +403,39 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.Pipeline", + "type": "Type", + "tags": [], + "label": "Pipeline", + "description": [ + "\nThe pipeline object." + ], + "signature": [ + "{ processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }" + ], + "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "integrationAssistant", "id": "def-common.PLUGIN_ID", @@ -987,6 +463,68 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.RelatedRequestBody", + "type": "Type", + "tags": [], + "label": "RelatedRequestBody", + "description": [], + "signature": [ + "{ connectorId: string; packageName: string; rawSamples: string[]; datastreamName: string; currentPipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; }" + ], + "path": "x-pack/plugins/integration_assistant/common/api/related/related_route.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.RelatedResponse", + "type": "Type", + "tags": [], + "label": "RelatedResponse", + "description": [], + "signature": [ + "{ results: { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }; }" + ], + "path": "x-pack/plugins/integration_assistant/common/api/related/related_route.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "integrationAssistant", "id": "def-common.TEST_PIPELINE_PATH", @@ -1000,6 +538,1353 @@ "initialIsOpen": false } ], - "objects": [] + "objects": [ + { + "parentPluginId": "integrationAssistant", + "id": "def-common.BuildIntegrationRequestBody", + "type": "Object", + "tags": [], + "label": "BuildIntegrationRequestBody", + "description": [], + "signature": [ + "Zod.ZodObject<{ integration: Zod.ZodObject<{ name: Zod.ZodString; title: Zod.ZodString; description: Zod.ZodString; dataStreams: Zod.ZodArray, \"many\">; rawSamples: Zod.ZodArray; pipeline: Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>; docs: Zod.ZodArray, \"many\">; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }[]; logo?: string | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }[]; logo?: string | undefined; }; }, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }[]; logo?: string | undefined; }; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.CategorizationRequestBody", + "type": "Object", + "tags": [], + "label": "CategorizationRequestBody", + "description": [], + "signature": [ + "Zod.ZodObject<{ packageName: Zod.ZodString; datastreamName: Zod.ZodString; rawSamples: Zod.ZodArray; currentPipeline: Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>; connectorId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; datastreamName: string; currentPipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; }, { connectorId: string; packageName: string; rawSamples: string[]; datastreamName: string; currentPipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.CategorizationResponse", + "type": "Object", + "tags": [], + "label": "CategorizationResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ results: Zod.ZodObject<{ docs: Zod.ZodArray, \"many\">; pipeline: Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }, { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }>; }, \"strip\", Zod.ZodTypeAny, { results: { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }; }, { results: { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/categorization/categorization_route.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.CheckPipelineRequestBody", + "type": "Object", + "tags": [], + "label": "CheckPipelineRequestBody", + "description": [], + "signature": [ + "Zod.ZodObject<{ rawSamples: Zod.ZodArray; pipeline: Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; }, { rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.CheckPipelineResponse", + "type": "Object", + "tags": [], + "label": "CheckPipelineResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ pipelineResults: Zod.ZodArray, \"many\">; errors: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { pipelineResults: {}[]; errors?: {}[] | undefined; }, { pipelineResults: {}[]; errors?: {}[] | undefined; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/check_pipeline/check_pipeline.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.Datastream", + "type": "Object", + "tags": [], + "label": "Datastream", + "description": [], + "signature": [ + "Zod.ZodObject<{ name: Zod.ZodString; title: Zod.ZodString; description: Zod.ZodString; inputTypes: Zod.ZodArray, \"many\">; rawSamples: Zod.ZodArray; pipeline: Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>; docs: Zod.ZodArray, \"many\">; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.EcsMappingRequestBody", + "type": "Object", + "tags": [], + "label": "EcsMappingRequestBody", + "description": [], + "signature": [ + "Zod.ZodObject<{ packageName: Zod.ZodString; datastreamName: Zod.ZodString; rawSamples: Zod.ZodArray; mapping: Zod.ZodOptional>; connectorId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; datastreamName: string; mapping?: {} | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; datastreamName: string; mapping?: {} | undefined; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.EcsMappingResponse", + "type": "Object", + "tags": [], + "label": "EcsMappingResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ results: Zod.ZodObject<{ mapping: Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>; pipeline: Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; mapping: {}; }, { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; mapping: {}; }>; }, \"strip\", Zod.ZodTypeAny, { results: { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; mapping: {}; }; }, { results: { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; mapping: {}; }; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/ecs/ecs_route.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.ESProcessorItem", + "type": "Object", + "tags": [], + "label": "ESProcessorItem", + "description": [], + "signature": [ + "Zod.ZodType<", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + ", Zod.ZodTypeDef, ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + ">" + ], + "path": "x-pack/plugins/integration_assistant/common/api/model/processor_attributes.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.InputType", + "type": "Object", + "tags": [], + "label": "InputType", + "description": [], + "signature": [ + "Zod.ZodEnum<[\"aws_cloudwatch\", \"aws_s3\", \"azure_blob_storage\", \"azure_eventhub\", \"cloudfoundry\", \"filestream\", \"gcp_pubsub\", \"gcs\", \"http_endpoint\", \"journald\", \"kafka\", \"tcp\", \"udp\"]>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.Integration", + "type": "Object", + "tags": [], + "label": "Integration", + "description": [], + "signature": [ + "Zod.ZodObject<{ name: Zod.ZodString; title: Zod.ZodString; description: Zod.ZodString; dataStreams: Zod.ZodArray, \"many\">; rawSamples: Zod.ZodArray; pipeline: Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>; docs: Zod.ZodArray, \"many\">; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws_cloudwatch\" | \"aws_s3\" | \"azure_blob_storage\" | \"azure_eventhub\" | \"cloudfoundry\" | \"filestream\" | \"gcp_pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }[]; logo?: string | undefined; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.Pipeline", + "type": "Object", + "tags": [], + "label": "Pipeline", + "description": [], + "signature": [ + "Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.RelatedRequestBody", + "type": "Object", + "tags": [], + "label": "RelatedRequestBody", + "description": [], + "signature": [ + "Zod.ZodObject<{ packageName: Zod.ZodString; datastreamName: Zod.ZodString; rawSamples: Zod.ZodArray; currentPipeline: Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>; connectorId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; datastreamName: string; currentPipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; }, { connectorId: string; packageName: string; rawSamples: string[]; datastreamName: string; currentPipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/related/related_route.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "integrationAssistant", + "id": "def-common.RelatedResponse", + "type": "Object", + "tags": [], + "label": "RelatedResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ results: Zod.ZodObject<{ docs: Zod.ZodArray, \"many\">; pipeline: Zod.ZodObject<{ name: Zod.ZodOptional; description: Zod.ZodOptional; version: Zod.ZodOptional; processors: Zod.ZodArray, \"many\">; on_failure: Zod.ZodOptional, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }, { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }, { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }>; }, \"strip\", Zod.ZodTypeAny, { results: { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }; }, { results: { pipeline: { processors: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[]; name?: string | undefined; description?: string | undefined; version?: number | undefined; on_failure?: ", + { + "pluginId": "integrationAssistant", + "scope": "common", + "docId": "kibIntegrationAssistantPluginApi", + "section": "def-common.ESProcessorItem", + "text": "ESProcessorItem" + }, + "[] | undefined; }; docs: {}[]; }; }>" + ], + "path": "x-pack/plugins/integration_assistant/common/api/related/related_route.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ] } } \ No newline at end of file diff --git a/api_docs/integration_assistant.mdx b/api_docs/integration_assistant.mdx index 3843c88387c928..73b904ecb97c2d 100644 --- a/api_docs/integration_assistant.mdx +++ b/api_docs/integration_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/integrationAssistant title: "integrationAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the integrationAssistant plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'integrationAssistant'] --- import integrationAssistantObj from './integration_assistant.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/secur | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 69 | 0 | 69 | 0 | +| 38 | 0 | 33 | 1 | ## Server @@ -33,11 +33,8 @@ Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/secur ## Common -### Interfaces - - -### Enums - +### Objects + ### Consts, variables and types diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 357d85637bd47a..871aeba226a58e 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/investigate.mdx b/api_docs/investigate.mdx index 8de337c3c95d46..18caa601857ed7 100644 --- a/api_docs/investigate.mdx +++ b/api_docs/investigate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigate title: "investigate" image: https://source.unsplash.com/400x175/?github description: API docs for the investigate plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigate'] --- import investigateObj from './investigate.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index b06c821e80cdae..767a83fd2f9b97 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index fa8abc5d1abe4a..292449afdca28b 100644 --- a/api_docs/kbn_actions_types.mdx +++ b/api_docs/kbn_actions_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-actions-types title: "@kbn/actions-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/actions-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 01e342ac33cb78..b5f13d0ca6c0c0 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_pattern_analysis.mdx b/api_docs/kbn_aiops_log_pattern_analysis.mdx index ff4acdfbeb7597..eb59d7fe3fd706 100644 --- a/api_docs/kbn_aiops_log_pattern_analysis.mdx +++ b/api_docs/kbn_aiops_log_pattern_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-pattern-analysis title: "@kbn/aiops-log-pattern-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-pattern-analysis plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-pattern-analysis'] --- import kbnAiopsLogPatternAnalysisObj from './kbn_aiops_log_pattern_analysis.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_rate_analysis.mdx b/api_docs/kbn_aiops_log_rate_analysis.mdx index ec680f789947b5..e54e82a6351ae0 100644 --- a/api_docs/kbn_aiops_log_rate_analysis.mdx +++ b/api_docs/kbn_aiops_log_rate_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-rate-analysis title: "@kbn/aiops-log-rate-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-rate-analysis plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-rate-analysis'] --- import kbnAiopsLogRateAnalysisObj from './kbn_aiops_log_rate_analysis.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index 227b93cbe6c809..e1ef20d3f3fc87 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_comparators.mdx b/api_docs/kbn_alerting_comparators.mdx index e8909afd96cd6e..bc0c50bbd4d120 100644 --- a/api_docs/kbn_alerting_comparators.mdx +++ b/api_docs/kbn_alerting_comparators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-comparators title: "@kbn/alerting-comparators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-comparators plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-comparators'] --- import kbnAlertingComparatorsObj from './kbn_alerting_comparators.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 7162776bea72e0..0a6362b629c29e 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerting_types.mdx b/api_docs/kbn_alerting_types.mdx index df3d3c1ebde231..e2ea27e9793463 100644 --- a/api_docs/kbn_alerting_types.mdx +++ b/api_docs/kbn_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-types title: "@kbn/alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-types'] --- import kbnAlertingTypesObj from './kbn_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.devdocs.json b/api_docs/kbn_alerts_as_data_utils.devdocs.json index 01dc34570dabce..ddb8b8183ad05c 100644 --- a/api_docs/kbn_alerts_as_data_utils.devdocs.json +++ b/api_docs/kbn_alerts_as_data_utils.devdocs.json @@ -450,7 +450,7 @@ "label": "StackAlert", "description": [], "signature": [ - "{} & { 'kibana.alert.evaluation.conditions'?: string | undefined; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | undefined; 'kibana.alert.title'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.consecutive_matches'?: string | number | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.timestamp'?: string | number | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; }" + "{} & { 'kibana.alert.evaluation.conditions'?: string | undefined; 'kibana.alert.evaluation.threshold'?: string | number | undefined; 'kibana.alert.evaluation.value'?: string | undefined; 'kibana.alert.title'?: string | undefined; } & { '@timestamp': string | number; 'kibana.alert.instance.id': string; 'kibana.alert.rule.category': string; 'kibana.alert.rule.consumer': string; 'kibana.alert.rule.name': string; 'kibana.alert.rule.producer': string; 'kibana.alert.rule.revision': string | number; 'kibana.alert.rule.rule_type_id': string; 'kibana.alert.rule.uuid': string; 'kibana.alert.status': string; 'kibana.alert.uuid': string; 'kibana.space_ids': string[]; } & { 'event.action'?: string | undefined; 'event.kind'?: string | undefined; 'kibana.alert.action_group'?: string | undefined; 'kibana.alert.case_ids'?: string[] | undefined; 'kibana.alert.consecutive_matches'?: string | number | undefined; 'kibana.alert.duration.us'?: string | number | undefined; 'kibana.alert.end'?: string | number | undefined; 'kibana.alert.flapping'?: boolean | undefined; 'kibana.alert.flapping_history'?: boolean[] | undefined; 'kibana.alert.last_detected'?: string | number | undefined; 'kibana.alert.maintenance_window_ids'?: string[] | undefined; 'kibana.alert.reason'?: string | undefined; 'kibana.alert.rule.execution.timestamp'?: string | number | undefined; 'kibana.alert.rule.execution.uuid'?: string | undefined; 'kibana.alert.rule.parameters'?: unknown; 'kibana.alert.rule.tags'?: string[] | undefined; 'kibana.alert.start'?: string | number | undefined; 'kibana.alert.time_range'?: { gte?: string | number | undefined; lte?: string | number | undefined; } | undefined; 'kibana.alert.url'?: string | undefined; 'kibana.alert.workflow_assignee_ids'?: string[] | undefined; 'kibana.alert.workflow_status'?: string | undefined; 'kibana.alert.workflow_tags'?: string[] | undefined; 'kibana.version'?: string | undefined; tags?: string[] | undefined; } & { '@timestamp': string | number; 'ecs.version': string; } & { 'agent.build.original'?: string | undefined; 'agent.ephemeral_id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'agent.type'?: string | undefined; 'agent.version'?: string | undefined; 'client.address'?: string | undefined; 'client.as.number'?: string | number | undefined; 'client.as.organization.name'?: string | undefined; 'client.bytes'?: string | number | undefined; 'client.domain'?: string | undefined; 'client.geo.city_name'?: string | undefined; 'client.geo.continent_code'?: string | undefined; 'client.geo.continent_name'?: string | undefined; 'client.geo.country_iso_code'?: string | undefined; 'client.geo.country_name'?: string | undefined; 'client.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'client.geo.name'?: string | undefined; 'client.geo.postal_code'?: string | undefined; 'client.geo.region_iso_code'?: string | undefined; 'client.geo.region_name'?: string | undefined; 'client.geo.timezone'?: string | undefined; 'client.ip'?: string | undefined; 'client.mac'?: string | undefined; 'client.nat.ip'?: string | undefined; 'client.nat.port'?: string | number | undefined; 'client.packets'?: string | number | undefined; 'client.port'?: string | number | undefined; 'client.registered_domain'?: string | undefined; 'client.subdomain'?: string | undefined; 'client.top_level_domain'?: string | undefined; 'client.user.domain'?: string | undefined; 'client.user.email'?: string | undefined; 'client.user.full_name'?: string | undefined; 'client.user.group.domain'?: string | undefined; 'client.user.group.id'?: string | undefined; 'client.user.group.name'?: string | undefined; 'client.user.hash'?: string | undefined; 'client.user.id'?: string | undefined; 'client.user.name'?: string | undefined; 'client.user.roles'?: string[] | undefined; 'cloud.account.id'?: string | undefined; 'cloud.account.name'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'cloud.instance.name'?: string | undefined; 'cloud.machine.type'?: string | undefined; 'cloud.origin.account.id'?: string | undefined; 'cloud.origin.account.name'?: string | undefined; 'cloud.origin.availability_zone'?: string | undefined; 'cloud.origin.instance.id'?: string | undefined; 'cloud.origin.instance.name'?: string | undefined; 'cloud.origin.machine.type'?: string | undefined; 'cloud.origin.project.id'?: string | undefined; 'cloud.origin.project.name'?: string | undefined; 'cloud.origin.provider'?: string | undefined; 'cloud.origin.region'?: string | undefined; 'cloud.origin.service.name'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.project.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.service.name'?: string | undefined; 'cloud.target.account.id'?: string | undefined; 'cloud.target.account.name'?: string | undefined; 'cloud.target.availability_zone'?: string | undefined; 'cloud.target.instance.id'?: string | undefined; 'cloud.target.instance.name'?: string | undefined; 'cloud.target.machine.type'?: string | undefined; 'cloud.target.project.id'?: string | undefined; 'cloud.target.project.name'?: string | undefined; 'cloud.target.provider'?: string | undefined; 'cloud.target.region'?: string | undefined; 'cloud.target.service.name'?: string | undefined; 'container.cpu.usage'?: string | number | undefined; 'container.disk.read.bytes'?: string | number | undefined; 'container.disk.write.bytes'?: string | number | undefined; 'container.id'?: string | undefined; 'container.image.hash.all'?: string[] | undefined; 'container.image.name'?: string | undefined; 'container.image.tag'?: string[] | undefined; 'container.labels'?: unknown; 'container.memory.usage'?: string | number | undefined; 'container.name'?: string | undefined; 'container.network.egress.bytes'?: string | number | undefined; 'container.network.ingress.bytes'?: string | number | undefined; 'container.runtime'?: string | undefined; 'container.security_context.privileged'?: boolean | undefined; 'destination.address'?: string | undefined; 'destination.as.number'?: string | number | undefined; 'destination.as.organization.name'?: string | undefined; 'destination.bytes'?: string | number | undefined; 'destination.domain'?: string | undefined; 'destination.geo.city_name'?: string | undefined; 'destination.geo.continent_code'?: string | undefined; 'destination.geo.continent_name'?: string | undefined; 'destination.geo.country_iso_code'?: string | undefined; 'destination.geo.country_name'?: string | undefined; 'destination.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'destination.geo.name'?: string | undefined; 'destination.geo.postal_code'?: string | undefined; 'destination.geo.region_iso_code'?: string | undefined; 'destination.geo.region_name'?: string | undefined; 'destination.geo.timezone'?: string | undefined; 'destination.ip'?: string | undefined; 'destination.mac'?: string | undefined; 'destination.nat.ip'?: string | undefined; 'destination.nat.port'?: string | number | undefined; 'destination.packets'?: string | number | undefined; 'destination.port'?: string | number | undefined; 'destination.registered_domain'?: string | undefined; 'destination.subdomain'?: string | undefined; 'destination.top_level_domain'?: string | undefined; 'destination.user.domain'?: string | undefined; 'destination.user.email'?: string | undefined; 'destination.user.full_name'?: string | undefined; 'destination.user.group.domain'?: string | undefined; 'destination.user.group.id'?: string | undefined; 'destination.user.group.name'?: string | undefined; 'destination.user.hash'?: string | undefined; 'destination.user.id'?: string | undefined; 'destination.user.name'?: string | undefined; 'destination.user.roles'?: string[] | undefined; 'device.id'?: string | undefined; 'device.manufacturer'?: string | undefined; 'device.model.identifier'?: string | undefined; 'device.model.name'?: string | undefined; 'dll.code_signature.digest_algorithm'?: string | undefined; 'dll.code_signature.exists'?: boolean | undefined; 'dll.code_signature.signing_id'?: string | undefined; 'dll.code_signature.status'?: string | undefined; 'dll.code_signature.subject_name'?: string | undefined; 'dll.code_signature.team_id'?: string | undefined; 'dll.code_signature.timestamp'?: string | number | undefined; 'dll.code_signature.trusted'?: boolean | undefined; 'dll.code_signature.valid'?: boolean | undefined; 'dll.hash.md5'?: string | undefined; 'dll.hash.sha1'?: string | undefined; 'dll.hash.sha256'?: string | undefined; 'dll.hash.sha384'?: string | undefined; 'dll.hash.sha512'?: string | undefined; 'dll.hash.ssdeep'?: string | undefined; 'dll.hash.tlsh'?: string | undefined; 'dll.name'?: string | undefined; 'dll.path'?: string | undefined; 'dll.pe.architecture'?: string | undefined; 'dll.pe.company'?: string | undefined; 'dll.pe.description'?: string | undefined; 'dll.pe.file_version'?: string | undefined; 'dll.pe.go_import_hash'?: string | undefined; 'dll.pe.go_imports'?: unknown; 'dll.pe.go_imports_names_entropy'?: string | number | undefined; 'dll.pe.go_imports_names_var_entropy'?: string | number | undefined; 'dll.pe.go_stripped'?: boolean | undefined; 'dll.pe.imphash'?: string | undefined; 'dll.pe.import_hash'?: string | undefined; 'dll.pe.imports'?: unknown[] | undefined; 'dll.pe.imports_names_entropy'?: string | number | undefined; 'dll.pe.imports_names_var_entropy'?: string | number | undefined; 'dll.pe.original_file_name'?: string | undefined; 'dll.pe.pehash'?: string | undefined; 'dll.pe.product'?: string | undefined; 'dll.pe.sections'?: { entropy?: string | number | undefined; name?: string | undefined; physical_size?: string | number | undefined; var_entropy?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'dns.answers'?: { class?: string | undefined; data?: string | undefined; name?: string | undefined; ttl?: string | number | undefined; type?: string | undefined; }[] | undefined; 'dns.header_flags'?: string[] | undefined; 'dns.id'?: string | undefined; 'dns.op_code'?: string | undefined; 'dns.question.class'?: string | undefined; 'dns.question.name'?: string | undefined; 'dns.question.registered_domain'?: string | undefined; 'dns.question.subdomain'?: string | undefined; 'dns.question.top_level_domain'?: string | undefined; 'dns.question.type'?: string | undefined; 'dns.resolved_ip'?: string[] | undefined; 'dns.response_code'?: string | undefined; 'dns.type'?: string | undefined; 'email.attachments'?: { 'file.extension'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.name'?: string | undefined; 'file.size'?: string | number | undefined; }[] | undefined; 'email.bcc.address'?: string[] | undefined; 'email.cc.address'?: string[] | undefined; 'email.content_type'?: string | undefined; 'email.delivery_timestamp'?: string | number | undefined; 'email.direction'?: string | undefined; 'email.from.address'?: string[] | undefined; 'email.local_id'?: string | undefined; 'email.message_id'?: string | undefined; 'email.origination_timestamp'?: string | number | undefined; 'email.reply_to.address'?: string[] | undefined; 'email.sender.address'?: string | undefined; 'email.subject'?: string | undefined; 'email.to.address'?: string[] | undefined; 'email.x_mailer'?: string | undefined; 'error.code'?: string | undefined; 'error.id'?: string | undefined; 'error.message'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.type'?: string | undefined; 'event.action'?: string | undefined; 'event.agent_id_status'?: string | undefined; 'event.category'?: string[] | undefined; 'event.code'?: string | undefined; 'event.created'?: string | number | undefined; 'event.dataset'?: string | undefined; 'event.duration'?: string | number | undefined; 'event.end'?: string | number | undefined; 'event.hash'?: string | undefined; 'event.id'?: string | undefined; 'event.ingested'?: string | number | undefined; 'event.kind'?: string | undefined; 'event.module'?: string | undefined; 'event.original'?: string | undefined; 'event.outcome'?: string | undefined; 'event.provider'?: string | undefined; 'event.reason'?: string | undefined; 'event.reference'?: string | undefined; 'event.risk_score'?: number | undefined; 'event.risk_score_norm'?: number | undefined; 'event.sequence'?: string | number | undefined; 'event.severity'?: string | number | undefined; 'event.start'?: string | number | undefined; 'event.timezone'?: string | undefined; 'event.type'?: string[] | undefined; 'event.url'?: string | undefined; 'faas.coldstart'?: boolean | undefined; 'faas.execution'?: string | undefined; 'faas.id'?: string | undefined; 'faas.name'?: string | undefined; 'faas.version'?: string | undefined; 'file.accessed'?: string | number | undefined; 'file.attributes'?: string[] | undefined; 'file.code_signature.digest_algorithm'?: string | undefined; 'file.code_signature.exists'?: boolean | undefined; 'file.code_signature.signing_id'?: string | undefined; 'file.code_signature.status'?: string | undefined; 'file.code_signature.subject_name'?: string | undefined; 'file.code_signature.team_id'?: string | undefined; 'file.code_signature.timestamp'?: string | number | undefined; 'file.code_signature.trusted'?: boolean | undefined; 'file.code_signature.valid'?: boolean | undefined; 'file.created'?: string | number | undefined; 'file.ctime'?: string | number | undefined; 'file.device'?: string | undefined; 'file.directory'?: string | undefined; 'file.drive_letter'?: string | undefined; 'file.elf.architecture'?: string | undefined; 'file.elf.byte_order'?: string | undefined; 'file.elf.cpu_type'?: string | undefined; 'file.elf.creation_date'?: string | number | undefined; 'file.elf.exports'?: unknown[] | undefined; 'file.elf.go_import_hash'?: string | undefined; 'file.elf.go_imports'?: unknown; 'file.elf.go_imports_names_entropy'?: string | number | undefined; 'file.elf.go_imports_names_var_entropy'?: string | number | undefined; 'file.elf.go_stripped'?: boolean | undefined; 'file.elf.header.abi_version'?: string | undefined; 'file.elf.header.class'?: string | undefined; 'file.elf.header.data'?: string | undefined; 'file.elf.header.entrypoint'?: string | number | undefined; 'file.elf.header.object_version'?: string | undefined; 'file.elf.header.os_abi'?: string | undefined; 'file.elf.header.type'?: string | undefined; 'file.elf.header.version'?: string | undefined; 'file.elf.import_hash'?: string | undefined; 'file.elf.imports'?: unknown[] | undefined; 'file.elf.imports_names_entropy'?: string | number | undefined; 'file.elf.imports_names_var_entropy'?: string | number | undefined; 'file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; var_entropy?: string | number | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'file.elf.shared_libraries'?: string[] | undefined; 'file.elf.telfhash'?: string | undefined; 'file.extension'?: string | undefined; 'file.fork_name'?: string | undefined; 'file.gid'?: string | undefined; 'file.group'?: string | undefined; 'file.hash.md5'?: string | undefined; 'file.hash.sha1'?: string | undefined; 'file.hash.sha256'?: string | undefined; 'file.hash.sha384'?: string | undefined; 'file.hash.sha512'?: string | undefined; 'file.hash.ssdeep'?: string | undefined; 'file.hash.tlsh'?: string | undefined; 'file.inode'?: string | undefined; 'file.macho.go_import_hash'?: string | undefined; 'file.macho.go_imports'?: unknown; 'file.macho.go_imports_names_entropy'?: string | number | undefined; 'file.macho.go_imports_names_var_entropy'?: string | number | undefined; 'file.macho.go_stripped'?: boolean | undefined; 'file.macho.import_hash'?: string | undefined; 'file.macho.imports'?: unknown[] | undefined; 'file.macho.imports_names_entropy'?: string | number | undefined; 'file.macho.imports_names_var_entropy'?: string | number | undefined; 'file.macho.sections'?: { entropy?: string | number | undefined; name?: string | undefined; physical_size?: string | number | undefined; var_entropy?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.macho.symhash'?: string | undefined; 'file.mime_type'?: string | undefined; 'file.mode'?: string | undefined; 'file.mtime'?: string | number | undefined; 'file.name'?: string | undefined; 'file.owner'?: string | undefined; 'file.path'?: string | undefined; 'file.pe.architecture'?: string | undefined; 'file.pe.company'?: string | undefined; 'file.pe.description'?: string | undefined; 'file.pe.file_version'?: string | undefined; 'file.pe.go_import_hash'?: string | undefined; 'file.pe.go_imports'?: unknown; 'file.pe.go_imports_names_entropy'?: string | number | undefined; 'file.pe.go_imports_names_var_entropy'?: string | number | undefined; 'file.pe.go_stripped'?: boolean | undefined; 'file.pe.imphash'?: string | undefined; 'file.pe.import_hash'?: string | undefined; 'file.pe.imports'?: unknown[] | undefined; 'file.pe.imports_names_entropy'?: string | number | undefined; 'file.pe.imports_names_var_entropy'?: string | number | undefined; 'file.pe.original_file_name'?: string | undefined; 'file.pe.pehash'?: string | undefined; 'file.pe.product'?: string | undefined; 'file.pe.sections'?: { entropy?: string | number | undefined; name?: string | undefined; physical_size?: string | number | undefined; var_entropy?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'file.size'?: string | number | undefined; 'file.target_path'?: string | undefined; 'file.type'?: string | undefined; 'file.uid'?: string | undefined; 'file.x509.alternative_names'?: string[] | undefined; 'file.x509.issuer.common_name'?: string[] | undefined; 'file.x509.issuer.country'?: string[] | undefined; 'file.x509.issuer.distinguished_name'?: string | undefined; 'file.x509.issuer.locality'?: string[] | undefined; 'file.x509.issuer.organization'?: string[] | undefined; 'file.x509.issuer.organizational_unit'?: string[] | undefined; 'file.x509.issuer.state_or_province'?: string[] | undefined; 'file.x509.not_after'?: string | number | undefined; 'file.x509.not_before'?: string | number | undefined; 'file.x509.public_key_algorithm'?: string | undefined; 'file.x509.public_key_curve'?: string | undefined; 'file.x509.public_key_exponent'?: string | number | undefined; 'file.x509.public_key_size'?: string | number | undefined; 'file.x509.serial_number'?: string | undefined; 'file.x509.signature_algorithm'?: string | undefined; 'file.x509.subject.common_name'?: string[] | undefined; 'file.x509.subject.country'?: string[] | undefined; 'file.x509.subject.distinguished_name'?: string | undefined; 'file.x509.subject.locality'?: string[] | undefined; 'file.x509.subject.organization'?: string[] | undefined; 'file.x509.subject.organizational_unit'?: string[] | undefined; 'file.x509.subject.state_or_province'?: string[] | undefined; 'file.x509.version_number'?: string | undefined; 'group.domain'?: string | undefined; 'group.id'?: string | undefined; 'group.name'?: string | undefined; 'host.architecture'?: string | undefined; 'host.boot.id'?: string | undefined; 'host.cpu.usage'?: string | number | undefined; 'host.disk.read.bytes'?: string | number | undefined; 'host.disk.write.bytes'?: string | number | undefined; 'host.domain'?: string | undefined; 'host.geo.city_name'?: string | undefined; 'host.geo.continent_code'?: string | undefined; 'host.geo.continent_name'?: string | undefined; 'host.geo.country_iso_code'?: string | undefined; 'host.geo.country_name'?: string | undefined; 'host.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'host.geo.name'?: string | undefined; 'host.geo.postal_code'?: string | undefined; 'host.geo.region_iso_code'?: string | undefined; 'host.geo.region_name'?: string | undefined; 'host.geo.timezone'?: string | undefined; 'host.hostname'?: string | undefined; 'host.id'?: string | undefined; 'host.ip'?: string[] | undefined; 'host.mac'?: string[] | undefined; 'host.name'?: string | undefined; 'host.network.egress.bytes'?: string | number | undefined; 'host.network.egress.packets'?: string | number | undefined; 'host.network.ingress.bytes'?: string | number | undefined; 'host.network.ingress.packets'?: string | number | undefined; 'host.os.family'?: string | undefined; 'host.os.full'?: string | undefined; 'host.os.kernel'?: string | undefined; 'host.os.name'?: string | undefined; 'host.os.platform'?: string | undefined; 'host.os.type'?: string | undefined; 'host.os.version'?: string | undefined; 'host.pid_ns_ino'?: string | undefined; 'host.risk.calculated_level'?: string | undefined; 'host.risk.calculated_score'?: number | undefined; 'host.risk.calculated_score_norm'?: number | undefined; 'host.risk.static_level'?: string | undefined; 'host.risk.static_score'?: number | undefined; 'host.risk.static_score_norm'?: number | undefined; 'host.type'?: string | undefined; 'host.uptime'?: string | number | undefined; 'http.request.body.bytes'?: string | number | undefined; 'http.request.body.content'?: string | undefined; 'http.request.bytes'?: string | number | undefined; 'http.request.id'?: string | undefined; 'http.request.method'?: string | undefined; 'http.request.mime_type'?: string | undefined; 'http.request.referrer'?: string | undefined; 'http.response.body.bytes'?: string | number | undefined; 'http.response.body.content'?: string | undefined; 'http.response.bytes'?: string | number | undefined; 'http.response.mime_type'?: string | undefined; 'http.response.status_code'?: string | number | undefined; 'http.version'?: string | undefined; labels?: unknown; 'log.file.path'?: string | undefined; 'log.level'?: string | undefined; 'log.logger'?: string | undefined; 'log.origin.file.line'?: string | number | undefined; 'log.origin.file.name'?: string | undefined; 'log.origin.function'?: string | undefined; 'log.syslog'?: unknown; message?: string | undefined; 'network.application'?: string | undefined; 'network.bytes'?: string | number | undefined; 'network.community_id'?: string | undefined; 'network.direction'?: string | undefined; 'network.forwarded_ip'?: string | undefined; 'network.iana_number'?: string | undefined; 'network.inner'?: unknown; 'network.name'?: string | undefined; 'network.packets'?: string | number | undefined; 'network.protocol'?: string | undefined; 'network.transport'?: string | undefined; 'network.type'?: string | undefined; 'network.vlan.id'?: string | undefined; 'network.vlan.name'?: string | undefined; 'observer.egress'?: unknown; 'observer.geo.city_name'?: string | undefined; 'observer.geo.continent_code'?: string | undefined; 'observer.geo.continent_name'?: string | undefined; 'observer.geo.country_iso_code'?: string | undefined; 'observer.geo.country_name'?: string | undefined; 'observer.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'observer.geo.name'?: string | undefined; 'observer.geo.postal_code'?: string | undefined; 'observer.geo.region_iso_code'?: string | undefined; 'observer.geo.region_name'?: string | undefined; 'observer.geo.timezone'?: string | undefined; 'observer.hostname'?: string | undefined; 'observer.ingress'?: unknown; 'observer.ip'?: string[] | undefined; 'observer.mac'?: string[] | undefined; 'observer.name'?: string | undefined; 'observer.os.family'?: string | undefined; 'observer.os.full'?: string | undefined; 'observer.os.kernel'?: string | undefined; 'observer.os.name'?: string | undefined; 'observer.os.platform'?: string | undefined; 'observer.os.type'?: string | undefined; 'observer.os.version'?: string | undefined; 'observer.product'?: string | undefined; 'observer.serial_number'?: string | undefined; 'observer.type'?: string | undefined; 'observer.vendor'?: string | undefined; 'observer.version'?: string | undefined; 'orchestrator.api_version'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.url'?: string | undefined; 'orchestrator.cluster.version'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'orchestrator.organization'?: string | undefined; 'orchestrator.resource.annotation'?: string[] | undefined; 'orchestrator.resource.id'?: string | undefined; 'orchestrator.resource.ip'?: string[] | undefined; 'orchestrator.resource.label'?: string[] | undefined; 'orchestrator.resource.name'?: string | undefined; 'orchestrator.resource.parent.type'?: string | undefined; 'orchestrator.resource.type'?: string | undefined; 'orchestrator.type'?: string | undefined; 'organization.id'?: string | undefined; 'organization.name'?: string | undefined; 'package.architecture'?: string | undefined; 'package.build_version'?: string | undefined; 'package.checksum'?: string | undefined; 'package.description'?: string | undefined; 'package.install_scope'?: string | undefined; 'package.installed'?: string | number | undefined; 'package.license'?: string | undefined; 'package.name'?: string | undefined; 'package.path'?: string | undefined; 'package.reference'?: string | undefined; 'package.size'?: string | number | undefined; 'package.type'?: string | undefined; 'package.version'?: string | undefined; 'process.args'?: string[] | undefined; 'process.args_count'?: string | number | undefined; 'process.code_signature.digest_algorithm'?: string | undefined; 'process.code_signature.exists'?: boolean | undefined; 'process.code_signature.signing_id'?: string | undefined; 'process.code_signature.status'?: string | undefined; 'process.code_signature.subject_name'?: string | undefined; 'process.code_signature.team_id'?: string | undefined; 'process.code_signature.timestamp'?: string | number | undefined; 'process.code_signature.trusted'?: boolean | undefined; 'process.code_signature.valid'?: boolean | undefined; 'process.command_line'?: string | undefined; 'process.elf.architecture'?: string | undefined; 'process.elf.byte_order'?: string | undefined; 'process.elf.cpu_type'?: string | undefined; 'process.elf.creation_date'?: string | number | undefined; 'process.elf.exports'?: unknown[] | undefined; 'process.elf.go_import_hash'?: string | undefined; 'process.elf.go_imports'?: unknown; 'process.elf.go_imports_names_entropy'?: string | number | undefined; 'process.elf.go_imports_names_var_entropy'?: string | number | undefined; 'process.elf.go_stripped'?: boolean | undefined; 'process.elf.header.abi_version'?: string | undefined; 'process.elf.header.class'?: string | undefined; 'process.elf.header.data'?: string | undefined; 'process.elf.header.entrypoint'?: string | number | undefined; 'process.elf.header.object_version'?: string | undefined; 'process.elf.header.os_abi'?: string | undefined; 'process.elf.header.type'?: string | undefined; 'process.elf.header.version'?: string | undefined; 'process.elf.import_hash'?: string | undefined; 'process.elf.imports'?: unknown[] | undefined; 'process.elf.imports_names_entropy'?: string | number | undefined; 'process.elf.imports_names_var_entropy'?: string | number | undefined; 'process.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; var_entropy?: string | number | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.elf.shared_libraries'?: string[] | undefined; 'process.elf.telfhash'?: string | undefined; 'process.end'?: string | number | undefined; 'process.entity_id'?: string | undefined; 'process.entry_leader.args'?: string[] | undefined; 'process.entry_leader.args_count'?: string | number | undefined; 'process.entry_leader.attested_groups.name'?: string | undefined; 'process.entry_leader.attested_user.id'?: string | undefined; 'process.entry_leader.attested_user.name'?: string | undefined; 'process.entry_leader.command_line'?: string | undefined; 'process.entry_leader.entity_id'?: string | undefined; 'process.entry_leader.entry_meta.source.ip'?: string | undefined; 'process.entry_leader.entry_meta.type'?: string | undefined; 'process.entry_leader.executable'?: string | undefined; 'process.entry_leader.group.id'?: string | undefined; 'process.entry_leader.group.name'?: string | undefined; 'process.entry_leader.interactive'?: boolean | undefined; 'process.entry_leader.name'?: string | undefined; 'process.entry_leader.parent.entity_id'?: string | undefined; 'process.entry_leader.parent.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.entity_id'?: string | undefined; 'process.entry_leader.parent.session_leader.pid'?: string | number | undefined; 'process.entry_leader.parent.session_leader.start'?: string | number | undefined; 'process.entry_leader.parent.session_leader.vpid'?: string | number | undefined; 'process.entry_leader.parent.start'?: string | number | undefined; 'process.entry_leader.parent.vpid'?: string | number | undefined; 'process.entry_leader.pid'?: string | number | undefined; 'process.entry_leader.real_group.id'?: string | undefined; 'process.entry_leader.real_group.name'?: string | undefined; 'process.entry_leader.real_user.id'?: string | undefined; 'process.entry_leader.real_user.name'?: string | undefined; 'process.entry_leader.same_as_process'?: boolean | undefined; 'process.entry_leader.saved_group.id'?: string | undefined; 'process.entry_leader.saved_group.name'?: string | undefined; 'process.entry_leader.saved_user.id'?: string | undefined; 'process.entry_leader.saved_user.name'?: string | undefined; 'process.entry_leader.start'?: string | number | undefined; 'process.entry_leader.supplemental_groups.id'?: string | undefined; 'process.entry_leader.supplemental_groups.name'?: string | undefined; 'process.entry_leader.tty'?: unknown; 'process.entry_leader.user.id'?: string | undefined; 'process.entry_leader.user.name'?: string | undefined; 'process.entry_leader.vpid'?: string | number | undefined; 'process.entry_leader.working_directory'?: string | undefined; 'process.env_vars'?: string[] | undefined; 'process.executable'?: string | undefined; 'process.exit_code'?: string | number | undefined; 'process.group_leader.args'?: string[] | undefined; 'process.group_leader.args_count'?: string | number | undefined; 'process.group_leader.command_line'?: string | undefined; 'process.group_leader.entity_id'?: string | undefined; 'process.group_leader.executable'?: string | undefined; 'process.group_leader.group.id'?: string | undefined; 'process.group_leader.group.name'?: string | undefined; 'process.group_leader.interactive'?: boolean | undefined; 'process.group_leader.name'?: string | undefined; 'process.group_leader.pid'?: string | number | undefined; 'process.group_leader.real_group.id'?: string | undefined; 'process.group_leader.real_group.name'?: string | undefined; 'process.group_leader.real_user.id'?: string | undefined; 'process.group_leader.real_user.name'?: string | undefined; 'process.group_leader.same_as_process'?: boolean | undefined; 'process.group_leader.saved_group.id'?: string | undefined; 'process.group_leader.saved_group.name'?: string | undefined; 'process.group_leader.saved_user.id'?: string | undefined; 'process.group_leader.saved_user.name'?: string | undefined; 'process.group_leader.start'?: string | number | undefined; 'process.group_leader.supplemental_groups.id'?: string | undefined; 'process.group_leader.supplemental_groups.name'?: string | undefined; 'process.group_leader.tty'?: unknown; 'process.group_leader.user.id'?: string | undefined; 'process.group_leader.user.name'?: string | undefined; 'process.group_leader.vpid'?: string | number | undefined; 'process.group_leader.working_directory'?: string | undefined; 'process.hash.md5'?: string | undefined; 'process.hash.sha1'?: string | undefined; 'process.hash.sha256'?: string | undefined; 'process.hash.sha384'?: string | undefined; 'process.hash.sha512'?: string | undefined; 'process.hash.ssdeep'?: string | undefined; 'process.hash.tlsh'?: string | undefined; 'process.interactive'?: boolean | undefined; 'process.io'?: unknown; 'process.macho.go_import_hash'?: string | undefined; 'process.macho.go_imports'?: unknown; 'process.macho.go_imports_names_entropy'?: string | number | undefined; 'process.macho.go_imports_names_var_entropy'?: string | number | undefined; 'process.macho.go_stripped'?: boolean | undefined; 'process.macho.import_hash'?: string | undefined; 'process.macho.imports'?: unknown[] | undefined; 'process.macho.imports_names_entropy'?: string | number | undefined; 'process.macho.imports_names_var_entropy'?: string | number | undefined; 'process.macho.sections'?: { entropy?: string | number | undefined; name?: string | undefined; physical_size?: string | number | undefined; var_entropy?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.macho.symhash'?: string | undefined; 'process.name'?: string | undefined; 'process.parent.args'?: string[] | undefined; 'process.parent.args_count'?: string | number | undefined; 'process.parent.code_signature.digest_algorithm'?: string | undefined; 'process.parent.code_signature.exists'?: boolean | undefined; 'process.parent.code_signature.signing_id'?: string | undefined; 'process.parent.code_signature.status'?: string | undefined; 'process.parent.code_signature.subject_name'?: string | undefined; 'process.parent.code_signature.team_id'?: string | undefined; 'process.parent.code_signature.timestamp'?: string | number | undefined; 'process.parent.code_signature.trusted'?: boolean | undefined; 'process.parent.code_signature.valid'?: boolean | undefined; 'process.parent.command_line'?: string | undefined; 'process.parent.elf.architecture'?: string | undefined; 'process.parent.elf.byte_order'?: string | undefined; 'process.parent.elf.cpu_type'?: string | undefined; 'process.parent.elf.creation_date'?: string | number | undefined; 'process.parent.elf.exports'?: unknown[] | undefined; 'process.parent.elf.go_import_hash'?: string | undefined; 'process.parent.elf.go_imports'?: unknown; 'process.parent.elf.go_imports_names_entropy'?: string | number | undefined; 'process.parent.elf.go_imports_names_var_entropy'?: string | number | undefined; 'process.parent.elf.go_stripped'?: boolean | undefined; 'process.parent.elf.header.abi_version'?: string | undefined; 'process.parent.elf.header.class'?: string | undefined; 'process.parent.elf.header.data'?: string | undefined; 'process.parent.elf.header.entrypoint'?: string | number | undefined; 'process.parent.elf.header.object_version'?: string | undefined; 'process.parent.elf.header.os_abi'?: string | undefined; 'process.parent.elf.header.type'?: string | undefined; 'process.parent.elf.header.version'?: string | undefined; 'process.parent.elf.import_hash'?: string | undefined; 'process.parent.elf.imports'?: unknown[] | undefined; 'process.parent.elf.imports_names_entropy'?: string | number | undefined; 'process.parent.elf.imports_names_var_entropy'?: string | number | undefined; 'process.parent.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; var_entropy?: string | number | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'process.parent.elf.shared_libraries'?: string[] | undefined; 'process.parent.elf.telfhash'?: string | undefined; 'process.parent.end'?: string | number | undefined; 'process.parent.entity_id'?: string | undefined; 'process.parent.executable'?: string | undefined; 'process.parent.exit_code'?: string | number | undefined; 'process.parent.group.id'?: string | undefined; 'process.parent.group.name'?: string | undefined; 'process.parent.group_leader.entity_id'?: string | undefined; 'process.parent.group_leader.pid'?: string | number | undefined; 'process.parent.group_leader.start'?: string | number | undefined; 'process.parent.group_leader.vpid'?: string | number | undefined; 'process.parent.hash.md5'?: string | undefined; 'process.parent.hash.sha1'?: string | undefined; 'process.parent.hash.sha256'?: string | undefined; 'process.parent.hash.sha384'?: string | undefined; 'process.parent.hash.sha512'?: string | undefined; 'process.parent.hash.ssdeep'?: string | undefined; 'process.parent.hash.tlsh'?: string | undefined; 'process.parent.interactive'?: boolean | undefined; 'process.parent.macho.go_import_hash'?: string | undefined; 'process.parent.macho.go_imports'?: unknown; 'process.parent.macho.go_imports_names_entropy'?: string | number | undefined; 'process.parent.macho.go_imports_names_var_entropy'?: string | number | undefined; 'process.parent.macho.go_stripped'?: boolean | undefined; 'process.parent.macho.import_hash'?: string | undefined; 'process.parent.macho.imports'?: unknown[] | undefined; 'process.parent.macho.imports_names_entropy'?: string | number | undefined; 'process.parent.macho.imports_names_var_entropy'?: string | number | undefined; 'process.parent.macho.sections'?: { entropy?: string | number | undefined; name?: string | undefined; physical_size?: string | number | undefined; var_entropy?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.macho.symhash'?: string | undefined; 'process.parent.name'?: string | undefined; 'process.parent.pe.architecture'?: string | undefined; 'process.parent.pe.company'?: string | undefined; 'process.parent.pe.description'?: string | undefined; 'process.parent.pe.file_version'?: string | undefined; 'process.parent.pe.go_import_hash'?: string | undefined; 'process.parent.pe.go_imports'?: unknown; 'process.parent.pe.go_imports_names_entropy'?: string | number | undefined; 'process.parent.pe.go_imports_names_var_entropy'?: string | number | undefined; 'process.parent.pe.go_stripped'?: boolean | undefined; 'process.parent.pe.imphash'?: string | undefined; 'process.parent.pe.import_hash'?: string | undefined; 'process.parent.pe.imports'?: unknown[] | undefined; 'process.parent.pe.imports_names_entropy'?: string | number | undefined; 'process.parent.pe.imports_names_var_entropy'?: string | number | undefined; 'process.parent.pe.original_file_name'?: string | undefined; 'process.parent.pe.pehash'?: string | undefined; 'process.parent.pe.product'?: string | undefined; 'process.parent.pe.sections'?: { entropy?: string | number | undefined; name?: string | undefined; physical_size?: string | number | undefined; var_entropy?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.parent.pgid'?: string | number | undefined; 'process.parent.pid'?: string | number | undefined; 'process.parent.real_group.id'?: string | undefined; 'process.parent.real_group.name'?: string | undefined; 'process.parent.real_user.id'?: string | undefined; 'process.parent.real_user.name'?: string | undefined; 'process.parent.saved_group.id'?: string | undefined; 'process.parent.saved_group.name'?: string | undefined; 'process.parent.saved_user.id'?: string | undefined; 'process.parent.saved_user.name'?: string | undefined; 'process.parent.start'?: string | number | undefined; 'process.parent.supplemental_groups.id'?: string | undefined; 'process.parent.supplemental_groups.name'?: string | undefined; 'process.parent.thread.capabilities.effective'?: string[] | undefined; 'process.parent.thread.capabilities.permitted'?: string[] | undefined; 'process.parent.thread.id'?: string | number | undefined; 'process.parent.thread.name'?: string | undefined; 'process.parent.title'?: string | undefined; 'process.parent.tty'?: unknown; 'process.parent.uptime'?: string | number | undefined; 'process.parent.user.id'?: string | undefined; 'process.parent.user.name'?: string | undefined; 'process.parent.vpid'?: string | number | undefined; 'process.parent.working_directory'?: string | undefined; 'process.pe.architecture'?: string | undefined; 'process.pe.company'?: string | undefined; 'process.pe.description'?: string | undefined; 'process.pe.file_version'?: string | undefined; 'process.pe.go_import_hash'?: string | undefined; 'process.pe.go_imports'?: unknown; 'process.pe.go_imports_names_entropy'?: string | number | undefined; 'process.pe.go_imports_names_var_entropy'?: string | number | undefined; 'process.pe.go_stripped'?: boolean | undefined; 'process.pe.imphash'?: string | undefined; 'process.pe.import_hash'?: string | undefined; 'process.pe.imports'?: unknown[] | undefined; 'process.pe.imports_names_entropy'?: string | number | undefined; 'process.pe.imports_names_var_entropy'?: string | number | undefined; 'process.pe.original_file_name'?: string | undefined; 'process.pe.pehash'?: string | undefined; 'process.pe.product'?: string | undefined; 'process.pe.sections'?: { entropy?: string | number | undefined; name?: string | undefined; physical_size?: string | number | undefined; var_entropy?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'process.pgid'?: string | number | undefined; 'process.pid'?: string | number | undefined; 'process.previous.args'?: string[] | undefined; 'process.previous.args_count'?: string | number | undefined; 'process.previous.executable'?: string | undefined; 'process.real_group.id'?: string | undefined; 'process.real_group.name'?: string | undefined; 'process.real_user.id'?: string | undefined; 'process.real_user.name'?: string | undefined; 'process.saved_group.id'?: string | undefined; 'process.saved_group.name'?: string | undefined; 'process.saved_user.id'?: string | undefined; 'process.saved_user.name'?: string | undefined; 'process.session_leader.args'?: string[] | undefined; 'process.session_leader.args_count'?: string | number | undefined; 'process.session_leader.command_line'?: string | undefined; 'process.session_leader.entity_id'?: string | undefined; 'process.session_leader.executable'?: string | undefined; 'process.session_leader.group.id'?: string | undefined; 'process.session_leader.group.name'?: string | undefined; 'process.session_leader.interactive'?: boolean | undefined; 'process.session_leader.name'?: string | undefined; 'process.session_leader.parent.entity_id'?: string | undefined; 'process.session_leader.parent.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.entity_id'?: string | undefined; 'process.session_leader.parent.session_leader.pid'?: string | number | undefined; 'process.session_leader.parent.session_leader.start'?: string | number | undefined; 'process.session_leader.parent.session_leader.vpid'?: string | number | undefined; 'process.session_leader.parent.start'?: string | number | undefined; 'process.session_leader.parent.vpid'?: string | number | undefined; 'process.session_leader.pid'?: string | number | undefined; 'process.session_leader.real_group.id'?: string | undefined; 'process.session_leader.real_group.name'?: string | undefined; 'process.session_leader.real_user.id'?: string | undefined; 'process.session_leader.real_user.name'?: string | undefined; 'process.session_leader.same_as_process'?: boolean | undefined; 'process.session_leader.saved_group.id'?: string | undefined; 'process.session_leader.saved_group.name'?: string | undefined; 'process.session_leader.saved_user.id'?: string | undefined; 'process.session_leader.saved_user.name'?: string | undefined; 'process.session_leader.start'?: string | number | undefined; 'process.session_leader.supplemental_groups.id'?: string | undefined; 'process.session_leader.supplemental_groups.name'?: string | undefined; 'process.session_leader.tty'?: unknown; 'process.session_leader.user.id'?: string | undefined; 'process.session_leader.user.name'?: string | undefined; 'process.session_leader.vpid'?: string | number | undefined; 'process.session_leader.working_directory'?: string | undefined; 'process.start'?: string | number | undefined; 'process.supplemental_groups.id'?: string | undefined; 'process.supplemental_groups.name'?: string | undefined; 'process.thread.capabilities.effective'?: string[] | undefined; 'process.thread.capabilities.permitted'?: string[] | undefined; 'process.thread.id'?: string | number | undefined; 'process.thread.name'?: string | undefined; 'process.title'?: string | undefined; 'process.tty'?: unknown; 'process.uptime'?: string | number | undefined; 'process.user.id'?: string | undefined; 'process.user.name'?: string | undefined; 'process.vpid'?: string | number | undefined; 'process.working_directory'?: string | undefined; 'registry.data.bytes'?: string | undefined; 'registry.data.strings'?: string[] | undefined; 'registry.data.type'?: string | undefined; 'registry.hive'?: string | undefined; 'registry.key'?: string | undefined; 'registry.path'?: string | undefined; 'registry.value'?: string | undefined; 'related.hash'?: string[] | undefined; 'related.hosts'?: string[] | undefined; 'related.ip'?: string[] | undefined; 'related.user'?: string[] | undefined; 'rule.author'?: string[] | undefined; 'rule.category'?: string | undefined; 'rule.description'?: string | undefined; 'rule.id'?: string | undefined; 'rule.license'?: string | undefined; 'rule.name'?: string | undefined; 'rule.reference'?: string | undefined; 'rule.ruleset'?: string | undefined; 'rule.uuid'?: string | undefined; 'rule.version'?: string | undefined; 'server.address'?: string | undefined; 'server.as.number'?: string | number | undefined; 'server.as.organization.name'?: string | undefined; 'server.bytes'?: string | number | undefined; 'server.domain'?: string | undefined; 'server.geo.city_name'?: string | undefined; 'server.geo.continent_code'?: string | undefined; 'server.geo.continent_name'?: string | undefined; 'server.geo.country_iso_code'?: string | undefined; 'server.geo.country_name'?: string | undefined; 'server.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'server.geo.name'?: string | undefined; 'server.geo.postal_code'?: string | undefined; 'server.geo.region_iso_code'?: string | undefined; 'server.geo.region_name'?: string | undefined; 'server.geo.timezone'?: string | undefined; 'server.ip'?: string | undefined; 'server.mac'?: string | undefined; 'server.nat.ip'?: string | undefined; 'server.nat.port'?: string | number | undefined; 'server.packets'?: string | number | undefined; 'server.port'?: string | number | undefined; 'server.registered_domain'?: string | undefined; 'server.subdomain'?: string | undefined; 'server.top_level_domain'?: string | undefined; 'server.user.domain'?: string | undefined; 'server.user.email'?: string | undefined; 'server.user.full_name'?: string | undefined; 'server.user.group.domain'?: string | undefined; 'server.user.group.id'?: string | undefined; 'server.user.group.name'?: string | undefined; 'server.user.hash'?: string | undefined; 'server.user.id'?: string | undefined; 'server.user.name'?: string | undefined; 'server.user.roles'?: string[] | undefined; 'service.address'?: string | undefined; 'service.environment'?: string | undefined; 'service.ephemeral_id'?: string | undefined; 'service.id'?: string | undefined; 'service.name'?: string | undefined; 'service.node.name'?: string | undefined; 'service.node.role'?: string | undefined; 'service.node.roles'?: string[] | undefined; 'service.origin.address'?: string | undefined; 'service.origin.environment'?: string | undefined; 'service.origin.ephemeral_id'?: string | undefined; 'service.origin.id'?: string | undefined; 'service.origin.name'?: string | undefined; 'service.origin.node.name'?: string | undefined; 'service.origin.node.role'?: string | undefined; 'service.origin.node.roles'?: string[] | undefined; 'service.origin.state'?: string | undefined; 'service.origin.type'?: string | undefined; 'service.origin.version'?: string | undefined; 'service.state'?: string | undefined; 'service.target.address'?: string | undefined; 'service.target.environment'?: string | undefined; 'service.target.ephemeral_id'?: string | undefined; 'service.target.id'?: string | undefined; 'service.target.name'?: string | undefined; 'service.target.node.name'?: string | undefined; 'service.target.node.role'?: string | undefined; 'service.target.node.roles'?: string[] | undefined; 'service.target.state'?: string | undefined; 'service.target.type'?: string | undefined; 'service.target.version'?: string | undefined; 'service.type'?: string | undefined; 'service.version'?: string | undefined; 'source.address'?: string | undefined; 'source.as.number'?: string | number | undefined; 'source.as.organization.name'?: string | undefined; 'source.bytes'?: string | number | undefined; 'source.domain'?: string | undefined; 'source.geo.city_name'?: string | undefined; 'source.geo.continent_code'?: string | undefined; 'source.geo.continent_name'?: string | undefined; 'source.geo.country_iso_code'?: string | undefined; 'source.geo.country_name'?: string | undefined; 'source.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'source.geo.name'?: string | undefined; 'source.geo.postal_code'?: string | undefined; 'source.geo.region_iso_code'?: string | undefined; 'source.geo.region_name'?: string | undefined; 'source.geo.timezone'?: string | undefined; 'source.ip'?: string | undefined; 'source.mac'?: string | undefined; 'source.nat.ip'?: string | undefined; 'source.nat.port'?: string | number | undefined; 'source.packets'?: string | number | undefined; 'source.port'?: string | number | undefined; 'source.registered_domain'?: string | undefined; 'source.subdomain'?: string | undefined; 'source.top_level_domain'?: string | undefined; 'source.user.domain'?: string | undefined; 'source.user.email'?: string | undefined; 'source.user.full_name'?: string | undefined; 'source.user.group.domain'?: string | undefined; 'source.user.group.id'?: string | undefined; 'source.user.group.name'?: string | undefined; 'source.user.hash'?: string | undefined; 'source.user.id'?: string | undefined; 'source.user.name'?: string | undefined; 'source.user.roles'?: string[] | undefined; 'span.id'?: string | undefined; tags?: string[] | undefined; 'threat.enrichments'?: { indicator?: unknown; 'matched.atomic'?: string | undefined; 'matched.field'?: string | undefined; 'matched.id'?: string | undefined; 'matched.index'?: string | undefined; 'matched.occurred'?: string | number | undefined; 'matched.type'?: string | undefined; }[] | undefined; 'threat.feed.dashboard_id'?: string | undefined; 'threat.feed.description'?: string | undefined; 'threat.feed.name'?: string | undefined; 'threat.feed.reference'?: string | undefined; 'threat.framework'?: string | undefined; 'threat.group.alias'?: string[] | undefined; 'threat.group.id'?: string | undefined; 'threat.group.name'?: string | undefined; 'threat.group.reference'?: string | undefined; 'threat.indicator.as.number'?: string | number | undefined; 'threat.indicator.as.organization.name'?: string | undefined; 'threat.indicator.confidence'?: string | undefined; 'threat.indicator.description'?: string | undefined; 'threat.indicator.email.address'?: string | undefined; 'threat.indicator.file.accessed'?: string | number | undefined; 'threat.indicator.file.attributes'?: string[] | undefined; 'threat.indicator.file.code_signature.digest_algorithm'?: string | undefined; 'threat.indicator.file.code_signature.exists'?: boolean | undefined; 'threat.indicator.file.code_signature.signing_id'?: string | undefined; 'threat.indicator.file.code_signature.status'?: string | undefined; 'threat.indicator.file.code_signature.subject_name'?: string | undefined; 'threat.indicator.file.code_signature.team_id'?: string | undefined; 'threat.indicator.file.code_signature.timestamp'?: string | number | undefined; 'threat.indicator.file.code_signature.trusted'?: boolean | undefined; 'threat.indicator.file.code_signature.valid'?: boolean | undefined; 'threat.indicator.file.created'?: string | number | undefined; 'threat.indicator.file.ctime'?: string | number | undefined; 'threat.indicator.file.device'?: string | undefined; 'threat.indicator.file.directory'?: string | undefined; 'threat.indicator.file.drive_letter'?: string | undefined; 'threat.indicator.file.elf.architecture'?: string | undefined; 'threat.indicator.file.elf.byte_order'?: string | undefined; 'threat.indicator.file.elf.cpu_type'?: string | undefined; 'threat.indicator.file.elf.creation_date'?: string | number | undefined; 'threat.indicator.file.elf.exports'?: unknown[] | undefined; 'threat.indicator.file.elf.go_import_hash'?: string | undefined; 'threat.indicator.file.elf.go_imports'?: unknown; 'threat.indicator.file.elf.go_imports_names_entropy'?: string | number | undefined; 'threat.indicator.file.elf.go_imports_names_var_entropy'?: string | number | undefined; 'threat.indicator.file.elf.go_stripped'?: boolean | undefined; 'threat.indicator.file.elf.header.abi_version'?: string | undefined; 'threat.indicator.file.elf.header.class'?: string | undefined; 'threat.indicator.file.elf.header.data'?: string | undefined; 'threat.indicator.file.elf.header.entrypoint'?: string | number | undefined; 'threat.indicator.file.elf.header.object_version'?: string | undefined; 'threat.indicator.file.elf.header.os_abi'?: string | undefined; 'threat.indicator.file.elf.header.type'?: string | undefined; 'threat.indicator.file.elf.header.version'?: string | undefined; 'threat.indicator.file.elf.import_hash'?: string | undefined; 'threat.indicator.file.elf.imports'?: unknown[] | undefined; 'threat.indicator.file.elf.imports_names_entropy'?: string | number | undefined; 'threat.indicator.file.elf.imports_names_var_entropy'?: string | number | undefined; 'threat.indicator.file.elf.sections'?: { chi2?: string | number | undefined; entropy?: string | number | undefined; flags?: string | undefined; name?: string | undefined; physical_offset?: string | undefined; physical_size?: string | number | undefined; type?: string | undefined; var_entropy?: string | number | undefined; virtual_address?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.elf.segments'?: { sections?: string | undefined; type?: string | undefined; }[] | undefined; 'threat.indicator.file.elf.shared_libraries'?: string[] | undefined; 'threat.indicator.file.elf.telfhash'?: string | undefined; 'threat.indicator.file.extension'?: string | undefined; 'threat.indicator.file.fork_name'?: string | undefined; 'threat.indicator.file.gid'?: string | undefined; 'threat.indicator.file.group'?: string | undefined; 'threat.indicator.file.hash.md5'?: string | undefined; 'threat.indicator.file.hash.sha1'?: string | undefined; 'threat.indicator.file.hash.sha256'?: string | undefined; 'threat.indicator.file.hash.sha384'?: string | undefined; 'threat.indicator.file.hash.sha512'?: string | undefined; 'threat.indicator.file.hash.ssdeep'?: string | undefined; 'threat.indicator.file.hash.tlsh'?: string | undefined; 'threat.indicator.file.inode'?: string | undefined; 'threat.indicator.file.mime_type'?: string | undefined; 'threat.indicator.file.mode'?: string | undefined; 'threat.indicator.file.mtime'?: string | number | undefined; 'threat.indicator.file.name'?: string | undefined; 'threat.indicator.file.owner'?: string | undefined; 'threat.indicator.file.path'?: string | undefined; 'threat.indicator.file.pe.architecture'?: string | undefined; 'threat.indicator.file.pe.company'?: string | undefined; 'threat.indicator.file.pe.description'?: string | undefined; 'threat.indicator.file.pe.file_version'?: string | undefined; 'threat.indicator.file.pe.go_import_hash'?: string | undefined; 'threat.indicator.file.pe.go_imports'?: unknown; 'threat.indicator.file.pe.go_imports_names_entropy'?: string | number | undefined; 'threat.indicator.file.pe.go_imports_names_var_entropy'?: string | number | undefined; 'threat.indicator.file.pe.go_stripped'?: boolean | undefined; 'threat.indicator.file.pe.imphash'?: string | undefined; 'threat.indicator.file.pe.import_hash'?: string | undefined; 'threat.indicator.file.pe.imports'?: unknown[] | undefined; 'threat.indicator.file.pe.imports_names_entropy'?: string | number | undefined; 'threat.indicator.file.pe.imports_names_var_entropy'?: string | number | undefined; 'threat.indicator.file.pe.original_file_name'?: string | undefined; 'threat.indicator.file.pe.pehash'?: string | undefined; 'threat.indicator.file.pe.product'?: string | undefined; 'threat.indicator.file.pe.sections'?: { entropy?: string | number | undefined; name?: string | undefined; physical_size?: string | number | undefined; var_entropy?: string | number | undefined; virtual_size?: string | number | undefined; }[] | undefined; 'threat.indicator.file.size'?: string | number | undefined; 'threat.indicator.file.target_path'?: string | undefined; 'threat.indicator.file.type'?: string | undefined; 'threat.indicator.file.uid'?: string | undefined; 'threat.indicator.file.x509.alternative_names'?: string[] | undefined; 'threat.indicator.file.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.file.x509.issuer.country'?: string[] | undefined; 'threat.indicator.file.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.file.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.not_after'?: string | number | undefined; 'threat.indicator.file.x509.not_before'?: string | number | undefined; 'threat.indicator.file.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.file.x509.public_key_curve'?: string | undefined; 'threat.indicator.file.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.file.x509.public_key_size'?: string | number | undefined; 'threat.indicator.file.x509.serial_number'?: string | undefined; 'threat.indicator.file.x509.signature_algorithm'?: string | undefined; 'threat.indicator.file.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.file.x509.subject.country'?: string[] | undefined; 'threat.indicator.file.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.file.x509.subject.locality'?: string[] | undefined; 'threat.indicator.file.x509.subject.organization'?: string[] | undefined; 'threat.indicator.file.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.file.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.file.x509.version_number'?: string | undefined; 'threat.indicator.first_seen'?: string | number | undefined; 'threat.indicator.geo.city_name'?: string | undefined; 'threat.indicator.geo.continent_code'?: string | undefined; 'threat.indicator.geo.continent_name'?: string | undefined; 'threat.indicator.geo.country_iso_code'?: string | undefined; 'threat.indicator.geo.country_name'?: string | undefined; 'threat.indicator.geo.location'?: string | { type: string; coordinates: number[]; } | { lat: number; lon: number; } | { location: number[]; } | { location: string; } | undefined; 'threat.indicator.geo.name'?: string | undefined; 'threat.indicator.geo.postal_code'?: string | undefined; 'threat.indicator.geo.region_iso_code'?: string | undefined; 'threat.indicator.geo.region_name'?: string | undefined; 'threat.indicator.geo.timezone'?: string | undefined; 'threat.indicator.ip'?: string | undefined; 'threat.indicator.last_seen'?: string | number | undefined; 'threat.indicator.marking.tlp'?: string | undefined; 'threat.indicator.marking.tlp_version'?: string | undefined; 'threat.indicator.modified_at'?: string | number | undefined; 'threat.indicator.name'?: string | undefined; 'threat.indicator.port'?: string | number | undefined; 'threat.indicator.provider'?: string | undefined; 'threat.indicator.reference'?: string | undefined; 'threat.indicator.registry.data.bytes'?: string | undefined; 'threat.indicator.registry.data.strings'?: string[] | undefined; 'threat.indicator.registry.data.type'?: string | undefined; 'threat.indicator.registry.hive'?: string | undefined; 'threat.indicator.registry.key'?: string | undefined; 'threat.indicator.registry.path'?: string | undefined; 'threat.indicator.registry.value'?: string | undefined; 'threat.indicator.scanner_stats'?: string | number | undefined; 'threat.indicator.sightings'?: string | number | undefined; 'threat.indicator.type'?: string | undefined; 'threat.indicator.url.domain'?: string | undefined; 'threat.indicator.url.extension'?: string | undefined; 'threat.indicator.url.fragment'?: string | undefined; 'threat.indicator.url.full'?: string | undefined; 'threat.indicator.url.original'?: string | undefined; 'threat.indicator.url.password'?: string | undefined; 'threat.indicator.url.path'?: string | undefined; 'threat.indicator.url.port'?: string | number | undefined; 'threat.indicator.url.query'?: string | undefined; 'threat.indicator.url.registered_domain'?: string | undefined; 'threat.indicator.url.scheme'?: string | undefined; 'threat.indicator.url.subdomain'?: string | undefined; 'threat.indicator.url.top_level_domain'?: string | undefined; 'threat.indicator.url.username'?: string | undefined; 'threat.indicator.x509.alternative_names'?: string[] | undefined; 'threat.indicator.x509.issuer.common_name'?: string[] | undefined; 'threat.indicator.x509.issuer.country'?: string[] | undefined; 'threat.indicator.x509.issuer.distinguished_name'?: string | undefined; 'threat.indicator.x509.issuer.locality'?: string[] | undefined; 'threat.indicator.x509.issuer.organization'?: string[] | undefined; 'threat.indicator.x509.issuer.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.issuer.state_or_province'?: string[] | undefined; 'threat.indicator.x509.not_after'?: string | number | undefined; 'threat.indicator.x509.not_before'?: string | number | undefined; 'threat.indicator.x509.public_key_algorithm'?: string | undefined; 'threat.indicator.x509.public_key_curve'?: string | undefined; 'threat.indicator.x509.public_key_exponent'?: string | number | undefined; 'threat.indicator.x509.public_key_size'?: string | number | undefined; 'threat.indicator.x509.serial_number'?: string | undefined; 'threat.indicator.x509.signature_algorithm'?: string | undefined; 'threat.indicator.x509.subject.common_name'?: string[] | undefined; 'threat.indicator.x509.subject.country'?: string[] | undefined; 'threat.indicator.x509.subject.distinguished_name'?: string | undefined; 'threat.indicator.x509.subject.locality'?: string[] | undefined; 'threat.indicator.x509.subject.organization'?: string[] | undefined; 'threat.indicator.x509.subject.organizational_unit'?: string[] | undefined; 'threat.indicator.x509.subject.state_or_province'?: string[] | undefined; 'threat.indicator.x509.version_number'?: string | undefined; 'threat.software.alias'?: string[] | undefined; 'threat.software.id'?: string | undefined; 'threat.software.name'?: string | undefined; 'threat.software.platforms'?: string[] | undefined; 'threat.software.reference'?: string | undefined; 'threat.software.type'?: string | undefined; 'threat.tactic.id'?: string[] | undefined; 'threat.tactic.name'?: string[] | undefined; 'threat.tactic.reference'?: string[] | undefined; 'threat.technique.id'?: string[] | undefined; 'threat.technique.name'?: string[] | undefined; 'threat.technique.reference'?: string[] | undefined; 'threat.technique.subtechnique.id'?: string[] | undefined; 'threat.technique.subtechnique.name'?: string[] | undefined; 'threat.technique.subtechnique.reference'?: string[] | undefined; 'tls.cipher'?: string | undefined; 'tls.client.certificate'?: string | undefined; 'tls.client.certificate_chain'?: string[] | undefined; 'tls.client.hash.md5'?: string | undefined; 'tls.client.hash.sha1'?: string | undefined; 'tls.client.hash.sha256'?: string | undefined; 'tls.client.issuer'?: string | undefined; 'tls.client.ja3'?: string | undefined; 'tls.client.not_after'?: string | number | undefined; 'tls.client.not_before'?: string | number | undefined; 'tls.client.server_name'?: string | undefined; 'tls.client.subject'?: string | undefined; 'tls.client.supported_ciphers'?: string[] | undefined; 'tls.client.x509.alternative_names'?: string[] | undefined; 'tls.client.x509.issuer.common_name'?: string[] | undefined; 'tls.client.x509.issuer.country'?: string[] | undefined; 'tls.client.x509.issuer.distinguished_name'?: string | undefined; 'tls.client.x509.issuer.locality'?: string[] | undefined; 'tls.client.x509.issuer.organization'?: string[] | undefined; 'tls.client.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.client.x509.issuer.state_or_province'?: string[] | undefined; 'tls.client.x509.not_after'?: string | number | undefined; 'tls.client.x509.not_before'?: string | number | undefined; 'tls.client.x509.public_key_algorithm'?: string | undefined; 'tls.client.x509.public_key_curve'?: string | undefined; 'tls.client.x509.public_key_exponent'?: string | number | undefined; 'tls.client.x509.public_key_size'?: string | number | undefined; 'tls.client.x509.serial_number'?: string | undefined; 'tls.client.x509.signature_algorithm'?: string | undefined; 'tls.client.x509.subject.common_name'?: string[] | undefined; 'tls.client.x509.subject.country'?: string[] | undefined; 'tls.client.x509.subject.distinguished_name'?: string | undefined; 'tls.client.x509.subject.locality'?: string[] | undefined; 'tls.client.x509.subject.organization'?: string[] | undefined; 'tls.client.x509.subject.organizational_unit'?: string[] | undefined; 'tls.client.x509.subject.state_or_province'?: string[] | undefined; 'tls.client.x509.version_number'?: string | undefined; 'tls.curve'?: string | undefined; 'tls.established'?: boolean | undefined; 'tls.next_protocol'?: string | undefined; 'tls.resumed'?: boolean | undefined; 'tls.server.certificate'?: string | undefined; 'tls.server.certificate_chain'?: string[] | undefined; 'tls.server.hash.md5'?: string | undefined; 'tls.server.hash.sha1'?: string | undefined; 'tls.server.hash.sha256'?: string | undefined; 'tls.server.issuer'?: string | undefined; 'tls.server.ja3s'?: string | undefined; 'tls.server.not_after'?: string | number | undefined; 'tls.server.not_before'?: string | number | undefined; 'tls.server.subject'?: string | undefined; 'tls.server.x509.alternative_names'?: string[] | undefined; 'tls.server.x509.issuer.common_name'?: string[] | undefined; 'tls.server.x509.issuer.country'?: string[] | undefined; 'tls.server.x509.issuer.distinguished_name'?: string | undefined; 'tls.server.x509.issuer.locality'?: string[] | undefined; 'tls.server.x509.issuer.organization'?: string[] | undefined; 'tls.server.x509.issuer.organizational_unit'?: string[] | undefined; 'tls.server.x509.issuer.state_or_province'?: string[] | undefined; 'tls.server.x509.not_after'?: string | number | undefined; 'tls.server.x509.not_before'?: string | number | undefined; 'tls.server.x509.public_key_algorithm'?: string | undefined; 'tls.server.x509.public_key_curve'?: string | undefined; 'tls.server.x509.public_key_exponent'?: string | number | undefined; 'tls.server.x509.public_key_size'?: string | number | undefined; 'tls.server.x509.serial_number'?: string | undefined; 'tls.server.x509.signature_algorithm'?: string | undefined; 'tls.server.x509.subject.common_name'?: string[] | undefined; 'tls.server.x509.subject.country'?: string[] | undefined; 'tls.server.x509.subject.distinguished_name'?: string | undefined; 'tls.server.x509.subject.locality'?: string[] | undefined; 'tls.server.x509.subject.organization'?: string[] | undefined; 'tls.server.x509.subject.organizational_unit'?: string[] | undefined; 'tls.server.x509.subject.state_or_province'?: string[] | undefined; 'tls.server.x509.version_number'?: string | undefined; 'tls.version'?: string | undefined; 'tls.version_protocol'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'url.domain'?: string | undefined; 'url.extension'?: string | undefined; 'url.fragment'?: string | undefined; 'url.full'?: string | undefined; 'url.original'?: string | undefined; 'url.password'?: string | undefined; 'url.path'?: string | undefined; 'url.port'?: string | number | undefined; 'url.query'?: string | undefined; 'url.registered_domain'?: string | undefined; 'url.scheme'?: string | undefined; 'url.subdomain'?: string | undefined; 'url.top_level_domain'?: string | undefined; 'url.username'?: string | undefined; 'user.changes.domain'?: string | undefined; 'user.changes.email'?: string | undefined; 'user.changes.full_name'?: string | undefined; 'user.changes.group.domain'?: string | undefined; 'user.changes.group.id'?: string | undefined; 'user.changes.group.name'?: string | undefined; 'user.changes.hash'?: string | undefined; 'user.changes.id'?: string | undefined; 'user.changes.name'?: string | undefined; 'user.changes.roles'?: string[] | undefined; 'user.domain'?: string | undefined; 'user.effective.domain'?: string | undefined; 'user.effective.email'?: string | undefined; 'user.effective.full_name'?: string | undefined; 'user.effective.group.domain'?: string | undefined; 'user.effective.group.id'?: string | undefined; 'user.effective.group.name'?: string | undefined; 'user.effective.hash'?: string | undefined; 'user.effective.id'?: string | undefined; 'user.effective.name'?: string | undefined; 'user.effective.roles'?: string[] | undefined; 'user.email'?: string | undefined; 'user.full_name'?: string | undefined; 'user.group.domain'?: string | undefined; 'user.group.id'?: string | undefined; 'user.group.name'?: string | undefined; 'user.hash'?: string | undefined; 'user.id'?: string | undefined; 'user.name'?: string | undefined; 'user.risk.calculated_level'?: string | undefined; 'user.risk.calculated_score'?: number | undefined; 'user.risk.calculated_score_norm'?: number | undefined; 'user.risk.static_level'?: string | undefined; 'user.risk.static_score'?: number | undefined; 'user.risk.static_score_norm'?: number | undefined; 'user.roles'?: string[] | undefined; 'user.target.domain'?: string | undefined; 'user.target.email'?: string | undefined; 'user.target.full_name'?: string | undefined; 'user.target.group.domain'?: string | undefined; 'user.target.group.id'?: string | undefined; 'user.target.group.name'?: string | undefined; 'user.target.hash'?: string | undefined; 'user.target.id'?: string | undefined; 'user.target.name'?: string | undefined; 'user.target.roles'?: string[] | undefined; 'user_agent.device.name'?: string | undefined; 'user_agent.name'?: string | undefined; 'user_agent.original'?: string | undefined; 'user_agent.os.family'?: string | undefined; 'user_agent.os.full'?: string | undefined; 'user_agent.os.kernel'?: string | undefined; 'user_agent.os.name'?: string | undefined; 'user_agent.os.platform'?: string | undefined; 'user_agent.os.type'?: string | undefined; 'user_agent.os.version'?: string | undefined; 'user_agent.version'?: string | undefined; 'vulnerability.category'?: string[] | undefined; 'vulnerability.classification'?: string | undefined; 'vulnerability.description'?: string | undefined; 'vulnerability.enumeration'?: string | undefined; 'vulnerability.id'?: string | undefined; 'vulnerability.reference'?: string | undefined; 'vulnerability.report_id'?: string | undefined; 'vulnerability.scanner.vendor'?: string | undefined; 'vulnerability.score.base'?: number | undefined; 'vulnerability.score.environmental'?: number | undefined; 'vulnerability.score.temporal'?: number | undefined; 'vulnerability.score.version'?: string | undefined; 'vulnerability.severity'?: string | undefined; }" ], "path": "packages/kbn-alerts-as-data-utils/src/schemas/generated/stack_schema.ts", "deprecated": false, diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 4abb5875169158..d85dceff868c6d 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 487d845867b34a..035f4691ada4a6 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index e46bfe5940a947..a61eec4b3e02c4 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index 351c1e8690d63d..143acf3a461c77 100644 --- a/api_docs/kbn_analytics_collection_utils.mdx +++ b/api_docs/kbn_analytics_collection_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-collection-utils title: "@kbn/analytics-collection-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-collection-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index d98fbe3570141e..f05c5655606377 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_data_view.mdx b/api_docs/kbn_apm_data_view.mdx index 307aeb06fe7b0d..f414c8a5b9a246 100644 --- a/api_docs/kbn_apm_data_view.mdx +++ b/api_docs/kbn_apm_data_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-data-view title: "@kbn/apm-data-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-data-view plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-data-view'] --- import kbnApmDataViewObj from './kbn_apm_data_view.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index d16fad88bde1c7..ad357a4144d508 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 5d4077f25f851f..50ece00b8f43b8 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 4078b2b9924981..f7328138d02610 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index a86bfa4aba3dc4..fc15dcbb32bfe0 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bfetch_error.mdx b/api_docs/kbn_bfetch_error.mdx index dfab0800e2a0f0..130c509e6e9789 100644 --- a/api_docs/kbn_bfetch_error.mdx +++ b/api_docs/kbn_bfetch_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bfetch-error title: "@kbn/bfetch-error" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bfetch-error plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bfetch-error'] --- import kbnBfetchErrorObj from './kbn_bfetch_error.devdocs.json'; diff --git a/api_docs/kbn_calculate_auto.mdx b/api_docs/kbn_calculate_auto.mdx index a831688cd6a16c..4a92028ce21336 100644 --- a/api_docs/kbn_calculate_auto.mdx +++ b/api_docs/kbn_calculate_auto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-auto title: "@kbn/calculate-auto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-auto plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-auto'] --- import kbnCalculateAutoObj from './kbn_calculate_auto.devdocs.json'; diff --git a/api_docs/kbn_calculate_width_from_char_count.mdx b/api_docs/kbn_calculate_width_from_char_count.mdx index 56e46c2ac595e1..4a731b72de36af 100644 --- a/api_docs/kbn_calculate_width_from_char_count.mdx +++ b/api_docs/kbn_calculate_width_from_char_count.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-width-from-char-count title: "@kbn/calculate-width-from-char-count" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-width-from-char-count plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-width-from-char-count'] --- import kbnCalculateWidthFromCharCountObj from './kbn_calculate_width_from_char_count.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 88e2fe42a4fec3..3649b11cba1271 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 43e66d95034f75..aa437b53ef5c50 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index 73f3e636779ac4..039d4cac81d550 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index a39b164e2e0668..8d529873460138 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-icons'] --- import kbnChartIconsObj from './kbn_chart_icons.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 7b14acf65b8385..c883c4ea501c6f 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index ed9607d16f834d..4d8d6b6f095dbb 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index a8c36eed58e93f..47a27d830b9b08 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index cf0dac9edba01c..9b7d2a0d649122 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index dfa158ac1ec18d..0d42b35f0f7e64 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mock.mdx b/api_docs/kbn_code_editor_mock.mdx index 54c2b42c47d0f4..6c18c1361f88c0 100644 --- a/api_docs/kbn_code_editor_mock.mdx +++ b/api_docs/kbn_code_editor_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mock title: "@kbn/code-editor-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mock plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mock'] --- import kbnCodeEditorMockObj from './kbn_code_editor_mock.devdocs.json'; diff --git a/api_docs/kbn_code_owners.mdx b/api_docs/kbn_code_owners.mdx index a4509947484f8d..4506e4957f745c 100644 --- a/api_docs/kbn_code_owners.mdx +++ b/api_docs/kbn_code_owners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-owners title: "@kbn/code-owners" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-owners plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-owners'] --- import kbnCodeOwnersObj from './kbn_code_owners.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 1ad88c024bbf82..f50fe7d50e1bc9 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 9b875d1e2e2acc..971b080bd7600c 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index e0e354ab7ad5d9..9ac2e856ef23d1 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.devdocs.json b/api_docs/kbn_config_schema.devdocs.json index 6b5e7c68c2f267..a78058f053a216 100644 --- a/api_docs/kbn_config_schema.devdocs.json +++ b/api_docs/kbn_config_schema.devdocs.json @@ -1169,9 +1169,11 @@ "type": "Function", "tags": [], "label": "validate", - "description": [], + "description": [ + "\nValidates the provided value against this schema.\nIf valid, the resulting output will be returned, otherwise an exception will be thrown." + ], "signature": [ - "(value: any, context?: Record, namespace?: string | undefined) => V" + "(value: unknown, context?: Record, namespace?: string | undefined) => V" ], "path": "packages/kbn-config-schema/src/types/type.ts", "deprecated": false, @@ -1180,12 +1182,12 @@ { "parentPluginId": "@kbn/config-schema", "id": "def-common.Type.validate.$1", - "type": "Any", + "type": "Unknown", "tags": [], "label": "value", "description": [], "signature": [ - "any" + "unknown" ], "path": "packages/kbn-config-schema/src/types/type.ts", "deprecated": false, @@ -1200,7 +1202,7 @@ "label": "context", "description": [], "signature": [ - "Record" + "Record" ], "path": "packages/kbn-config-schema/src/types/type.ts", "deprecated": false, @@ -1668,213 +1670,185 @@ "label": "Schema", "description": [], "signature": [ - "{ any: (options?: ", - "TypeOptions", - " | undefined) => ", + "{ allOf: { (itemType: ", + ", B extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", options?: ", - "ArrayOptions", - " | undefined) => ", + ", C extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "; boolean: (options?: ", - "TypeOptions", - " | undefined) => ", + ", D extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "; buffer: (options?: ", - "TypeOptions", - " | undefined) => ", + ", E extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "; byteSize: (options?: ", - "ByteSizeOptions", - " | undefined) => ", + ", F extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "<", + ", G extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.ByteSizeValue", - "text": "ByteSizeValue" + "section": "def-common.Props", + "text": "Props" }, - ">; conditional: (leftOperand: ", - "Reference", - ", rightOperand: A | ", - "Reference", - " | ", + ", H extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", equalType: ", + ", I extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", notEqualType: ", + ", J extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", options?: ", - "TypeOptions", - " | undefined) => ", + ", K extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.ConditionalType", - "text": "ConditionalType" + "section": "def-common.Props", + "text": "Props" }, - "; contextRef: (key: string) => ", - "ContextReference", - "; duration: (options?: ", - "DurationOptions", - " | undefined) => ", + ">(types: [", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; ip: (options?: ", - "IpOptions", - " | undefined) => ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; lazy: (id: string) => ", - "Lazy", - "; literal: (value: T) => ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; mapOf: (keyType: ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", valueType: ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", options?: ", - "MapOfOptions", - " | undefined) => ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ">; maybe: (type: ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ") => ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; nullable: (type: ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ") => ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; never: () => ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; number: (options?: ", - "NumberOptions", - " | undefined) => ", + "], options?: ", + "UnionTypeOptions", + " | undefined): ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -1882,205 +1856,185 @@ "section": "def-common.Type", "text": "Type" }, - "; object:

]?: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Props", - "text": "Props" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - ">(props: P, options?: ", - "ObjectTypeOptions", - "

| undefined) => ", + "<(A & B & C & D & E & F & G & H & I & J & K)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.ObjectType", - "text": "ObjectType" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - "

; oneOf: { (types: [", + "<(A & B & C & D & E & F & G & H & I & J & K)[K]>; }>>; , ", + ", B extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", C extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", D extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", E extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", F extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", G extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", H extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", I extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", J extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ">(types: [", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "], options?: ", - "UnionTypeOptions", - " | undefined): ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; (types: [", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" - }, - ", ", - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" - }, - ", ", - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, "], options?: ", "UnionTypeOptions", - " | undefined): ", + " | undefined): ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -2088,163 +2042,169 @@ "section": "def-common.Type", "text": "Type" }, - "; (types: [", + "]?: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - ", ", + "<(A & B & C & D & E & F & G & H & I & J)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - ", ", + "<(A & B & C & D & E & F & G & H & I & J)[K]>; }>>; , ", + ", B extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", C extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", D extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", E extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", F extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", G extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "], options?: ", - "UnionTypeOptions", - " | undefined): ", + ", H extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "; (types: [", + ", I extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" + }, + ">(types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "], options?: ", - "UnionTypeOptions", - " | undefined): ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; (types: [", + "], options?: ", + "UnionTypeOptions", + " | undefined): ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -2252,155 +2212,153 @@ "section": "def-common.Type", "text": "Type" }, - ", ", + "]?: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - ", ", + "<(A & B & C & D & E & F & G & H & I)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - ", ", + "<(A & B & C & D & E & F & G & H & I)[K]>; }>>; , ", + ", B extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", C extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", D extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "], options?: ", - "UnionTypeOptions", - " | undefined): ", + ", E extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "; (types: [", + ", F extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", G extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", H extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ">(types: [", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "], options?: ", - "UnionTypeOptions", - " | undefined): ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; (types: [", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", ", + "], options?: ", + "UnionTypeOptions", + " | undefined): ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -2408,85 +2366,137 @@ "section": "def-common.Type", "text": "Type" }, - "], options?: ", - "UnionTypeOptions", - " | undefined): ", + "]?: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - "; (types: [", + "<(A & B & C & D & E & F & G & H)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - ", ", + "<(A & B & C & D & E & F & G & H)[K]>; }>>; , ", + "section": "def-common.Props", + "text": "Props" + }, + ", B extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", ", + ", C extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "], options?: ", - "UnionTypeOptions", - " | undefined): ", + ", D extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "; (types: [", + ", E extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" + }, + ", F extends ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Props", + "text": "Props" + }, + ", G extends ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Props", + "text": "Props" + }, + ">(types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "], options?: ", + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", "UnionTypeOptions", - " | undefined): ", + " | undefined): ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -2494,43 +2504,121 @@ "section": "def-common.Type", "text": "Type" }, - "; (types: [", + "]?: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" }, ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "], options?: ", - "UnionTypeOptions", - " | undefined): ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "; (types: [", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "], options?: ", + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", "UnionTypeOptions", - " | undefined): ", + " | undefined): ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -2538,257 +2626,5712 @@ "section": "def-common.Type", "text": "Type" }, - "; }; recordOf: (keyType: ", + "]?: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - ", valueType: ", + "<(A & B & C & D & E & F)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - ", options?: ", - "RecordOfOptions", - " | undefined) => ", + "<(A & B & C & D & E & F)[K]>; }>>; >; stream: (options?: ", - "TypeOptions", - "<", - "Stream", - "> | undefined) => ", + ", B extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "<", - "Stream", - ">; siblingRef: (key: string) => ", - "SiblingReference", - "; string: (options?: ", - "StringOptions", - " | undefined) => ", + ", C extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "; uri: (options?: ", - "URIOptions", - " | undefined) => ", + ", D extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - "; }" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.TypeOf", - "type": "Type", - "tags": [], - "label": "TypeOf", - "description": [], - "signature": [ - "RT extends () => ", + ", E extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - " ? ReturnType[\"type\"] : RT extends ", + ">(types: [", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - " ? RT[\"type\"] : never" - ], - "path": "packages/kbn-config-schema/src/types/object_type.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], - "objects": [ - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.metaFields", - "type": "Object", - "tags": [], - "label": "metaFields", - "description": [], - "signature": [ - "{ readonly META_FIELD_X_OAS_ANY: \"x-oas-any-type\"; readonly META_FIELD_X_OAS_OPTIONAL: \"x-oas-optional\"; readonly META_FIELD_X_OAS_DEPRECATED: \"x-oas-deprecated\"; readonly META_FIELD_X_OAS_MAX_LENGTH: \"x-oas-max-length\"; readonly META_FIELD_X_OAS_MIN_LENGTH: \"x-oas-min-length\"; readonly META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES: \"x-oas-get-additional-properties\"; }" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema", - "type": "Object", - "tags": [], - "label": "schema", - "description": [], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + ", ", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.any", - "type": "Function", - "tags": [], - "label": "any", - "description": [], - "signature": [ - "(options?: ", - "TypeOptions", - " | undefined) => ", + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + " | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "; }>>; }; any: (options?: ", + "TypeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.AnyType", + "text": "AnyType" + }, + "; arrayOf: (itemType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", options?: ", + "ArrayOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; boolean: (options?: ", + "TypeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; buffer: (options?: ", + "TypeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; byteSize: (options?: ", + "ByteSizeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "<", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ByteSizeValue", + "text": "ByteSizeValue" + }, + ">; conditional: (leftOperand: ", + "Reference", + ", rightOperand: A | ", + "Reference", + " | ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", equalType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", notEqualType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", options?: ", + "TypeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ConditionalType", + "text": "ConditionalType" + }, + "; contextRef: (key: string) => ", + "ContextReference", + "; duration: (options?: ", + "DurationOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; intersection: { (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J & K)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J & K)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + " | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "; }>>; }; ip: (options?: ", + "IpOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; lazy: (id: string) => ", + "Lazy", + "; literal: (value: T) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; mapOf: (keyType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", valueType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", options?: ", + "MapOfOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ">; maybe: (type: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ") => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; nullable: (type: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ") => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; never: () => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; number: (options?: ", + "NumberOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; object:

(props: P, options?: ", + "ObjectTypeOptions", + "

| undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "

; oneOf: { (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; }; recordOf: (keyType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", valueType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", options?: ", + "RecordOfOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ">; stream: (options?: ", + "TypeOptions", + "<", + "Stream", + "> | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "<", + "Stream", + ">; siblingRef: (key: string) => ", + "SiblingReference", + "; string: (options?: ", + "StringOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; uri: (options?: ", + "URIOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "; }" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.TypeOf", + "type": "Type", + "tags": [], + "label": "TypeOf", + "description": [], + "signature": [ + "RT extends () => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + " ? ReturnType[\"type\"] : RT extends ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + " ? RT[\"type\"] : never" + ], + "path": "packages/kbn-config-schema/src/types/object_type.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.metaFields", + "type": "Object", + "tags": [], + "label": "metaFields", + "description": [], + "signature": [ + "{ readonly META_FIELD_X_OAS_ANY: \"x-oas-any-type\"; readonly META_FIELD_X_OAS_OPTIONAL: \"x-oas-optional\"; readonly META_FIELD_X_OAS_DEPRECATED: \"x-oas-deprecated\"; readonly META_FIELD_X_OAS_MAX_LENGTH: \"x-oas-max-length\"; readonly META_FIELD_X_OAS_MIN_LENGTH: \"x-oas-min-length\"; readonly META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES: \"x-oas-get-additional-properties\"; }" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.allOf", + "type": "Function", + "tags": [], + "label": "allOf", + "description": [], + "signature": [ + "{ (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J & K)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J & K)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + " | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "; }>>; }" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.any", + "type": "Function", + "tags": [], + "label": "any", + "description": [], + "signature": [ + "(options?: ", + "TypeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.AnyType", + "text": "AnyType" + } + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.any.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "TypeOptions", + " | undefined" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.arrayOf", + "type": "Function", + "tags": [], + "label": "arrayOf", + "description": [], + "signature": [ + "(itemType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", options?: ", + "ArrayOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.arrayOf.$1", + "type": "Object", + "tags": [], + "label": "itemType", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.arrayOf.$2", + "type": "CompoundType", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "ArrayOptions", + " | undefined" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.boolean", + "type": "Function", + "tags": [], + "label": "boolean", + "description": [], + "signature": [ + "(options?: ", + "TypeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.boolean.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "TypeOptions", + " | undefined" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.buffer", + "type": "Function", + "tags": [], + "label": "buffer", + "description": [], + "signature": [ + "(options?: ", + "TypeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.buffer.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "TypeOptions", + " | undefined" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.byteSize", + "type": "Function", + "tags": [], + "label": "byteSize", + "description": [], + "signature": [ + "(options?: ", + "ByteSizeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "<", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ByteSizeValue", + "text": "ByteSizeValue" + }, + ">" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.byteSize.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "ByteSizeOptions", + " | undefined" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.conditional", + "type": "Function", + "tags": [], + "label": "conditional", + "description": [], + "signature": [ + "(leftOperand: ", + "Reference", + ", rightOperand: A | ", + "Reference", + " | ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", equalType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", notEqualType: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + ", options?: ", + "TypeOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ConditionalType", + "text": "ConditionalType" + }, + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.conditional.$1", + "type": "Object", + "tags": [], + "label": "leftOperand", + "description": [], + "signature": [ + "Reference", + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.conditional.$2", + "type": "CompoundType", + "tags": [], + "label": "rightOperand", + "description": [], + "signature": [ + "A | ", + "Reference", + " | ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.conditional.$3", + "type": "Object", + "tags": [], + "label": "equalType", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.conditional.$4", + "type": "Object", + "tags": [], + "label": "notEqualType", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.conditional.$5", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "TypeOptions", + " | undefined" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.contextRef", + "type": "Function", + "tags": [], + "label": "contextRef", + "description": [], + "signature": [ + "(key: string) => ", + "ContextReference", + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.contextRef.$1", + "type": "string", + "tags": [], + "label": "key", + "description": [], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.duration", + "type": "Function", + "tags": [], + "label": "duration", + "description": [], + "signature": [ + "(options?: ", + "DurationOptions", + " | undefined) => ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.duration.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "DurationOptions", + " | undefined" + ], + "path": "packages/kbn-config-schema/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/config-schema", + "id": "def-common.schema.intersection", + "type": "Function", + "tags": [], + "label": "intersection", + "description": [], + "signature": [ + "{ (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J & K)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J & K)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I & J)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H & I)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G & H)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F & G)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E & F)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "]?: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D & E)[K]>; }>>; | undefined" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.arrayOf", - "type": "Function", - "tags": [], - "label": "arrayOf", - "description": [], - "signature": [ - "(itemType: ", + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Props", + "text": "Props" + }, + ", D extends ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.Props", + "text": "Props" }, - ", options?: ", - "ArrayOptions", - " | undefined) => ", + ">(types: [", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ + ", ", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.arrayOf.$1", - "type": "Object", - "tags": [], - "label": "itemType", - "description": [], - "signature": [ - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" - }, - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" }, + ", ", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.arrayOf.$2", - "type": "CompoundType", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "ArrayOptions", - " | undefined" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.boolean", - "type": "Function", - "tags": [], - "label": "boolean", - "description": [], - "signature": [ - "(options?: ", - "TypeOptions", - " | undefined) => ", + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -2796,41 +8339,73 @@ "section": "def-common.Type", "text": "Type" }, - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ + "]?: ", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.boolean.$1", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "TypeOptions", - " | undefined" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.buffer", - "type": "Function", - "tags": [], - "label": "buffer", - "description": [], - "signature": [ - "(options?: ", - "TypeOptions", - " | undefined) => ", + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C & D)[K]>; }>>; (types: [", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + ", ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" + }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -2838,111 +8413,57 @@ "section": "def-common.Type", "text": "Type" }, - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ + "]?: ", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.buffer.$1", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "TypeOptions", - " | undefined" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.byteSize", - "type": "Function", - "tags": [], - "label": "byteSize", - "description": [], - "signature": [ - "(options?: ", - "ByteSizeOptions", - " | undefined) => ", + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + "<(A & B & C)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - "<", + "<(A & B & C)[K]>; }>>; " - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ + ", B extends ", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.byteSize.$1", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "ByteSizeOptions", - " | undefined" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.conditional", - "type": "Function", - "tags": [], - "label": "conditional", - "description": [], - "signature": [ - "(leftOperand: ", - "Reference", - ", rightOperand: A | ", - "Reference", - " | ", + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Props", + "text": "Props" + }, + ">(types: [", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", equalType: ", + ", ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.ObjectType", + "text": "ObjectType" }, - ", notEqualType: ", + "], options?: ", + "UnionTypeOptions", + " | undefined): ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -2950,192 +8471,69 @@ "section": "def-common.Type", "text": "Type" }, - ", options?: ", - "TypeOptions", - " | undefined) => ", + "]?: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.ConditionalType", - "text": "ConditionalType" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ + "<(A & B)[K]> | undefined; } & { [K in keyof RequiredProperties]: ", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.conditional.$1", - "type": "Object", - "tags": [], - "label": "leftOperand", - "description": [], - "signature": [ - "Reference", - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" }, + "<(A & B)[K]>; }>>; | ", - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" - }, - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Props", + "text": "Props" }, + ">(types: [", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.conditional.$3", - "type": "Object", - "tags": [], - "label": "equalType", - "description": [], - "signature": [ - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" - }, - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.ObjectType", + "text": "ObjectType" }, + "], options?: ", + "UnionTypeOptions", + " | undefined): ", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.conditional.$4", - "type": "Object", - "tags": [], - "label": "notEqualType", - "description": [], - "signature": [ - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" - }, - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" }, + "]?: ", { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.conditional.$5", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "TypeOptions", - " | undefined" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.contextRef", - "type": "Function", - "tags": [], - "label": "contextRef", - "description": [], - "signature": [ - "(key: string) => ", - "ContextReference", - "" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.contextRef.$1", - "type": "string", - "tags": [], - "label": "key", - "description": [], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.duration", - "type": "Function", - "tags": [], - "label": "duration", - "description": [], - "signature": [ - "(options?: ", - "DurationOptions", - " | undefined) => ", + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.TypeOf", + "text": "TypeOf" + }, + " | undefined; } & { [K in keyof RequiredProperties]: ", { "pluginId": "@kbn/config-schema", "scope": "common", "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.Type", - "text": "Type" + "section": "def-common.TypeOf", + "text": "TypeOf" }, - "" + "; }>>; }" ], "path": "packages/kbn-config-schema/index.ts", "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "@kbn/config-schema", - "id": "def-common.schema.duration.$1", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "DurationOptions", - " | undefined" - ], - "path": "packages/kbn-config-schema/index.ts", - "deprecated": false, - "trackAdoption": false - } - ] + "trackAdoption": false }, { "parentPluginId": "@kbn/config-schema", diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index bb150234272260..7eb1ba384b302a 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 144 | 3 | 141 | 20 | +| 146 | 2 | 142 | 20 | ## Common diff --git a/api_docs/kbn_content_management_content_editor.devdocs.json b/api_docs/kbn_content_management_content_editor.devdocs.json index b8650daee4eb88..c6144ff95f63ba 100644 --- a/api_docs/kbn_content_management_content_editor.devdocs.json +++ b/api_docs/kbn_content_management_content_editor.devdocs.json @@ -186,7 +186,7 @@ "Item", "; isReadonly?: boolean | undefined; readonlyReason?: string | undefined; entityName: string; customValidators?: ", "CustomValidators", - " | undefined; }" + " | undefined; showActivityView?: boolean | undefined; }" ], "path": "packages/content-management/content_editor/src/open_content_editor.tsx", "deprecated": false, diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index 37dd4c0061cc29..11d11e8c99e804 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index b472318320313e..b8c232f7bda68c 100644 --- a/api_docs/kbn_content_management_tabbed_table_list_view.mdx +++ b/api_docs/kbn_content_management_tabbed_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-tabbed-table-list-view title: "@kbn/content-management-tabbed-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-tabbed-table-list-view plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-tabbed-table-list-view'] --- import kbnContentManagementTabbedTableListViewObj from './kbn_content_management_tabbed_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view.mdx b/api_docs/kbn_content_management_table_list_view.mdx index 5b851e5384110e..8edb473e684813 100644 --- a/api_docs/kbn_content_management_table_list_view.mdx +++ b/api_docs/kbn_content_management_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view title: "@kbn/content-management-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view'] --- import kbnContentManagementTableListViewObj from './kbn_content_management_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_common.devdocs.json b/api_docs/kbn_content_management_table_list_view_common.devdocs.json index 61f11d1c921f86..8bf94c542f624c 100644 --- a/api_docs/kbn_content_management_table_list_view_common.devdocs.json +++ b/api_docs/kbn_content_management_table_list_view_common.devdocs.json @@ -53,6 +53,34 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/content-management-table-list-view-common", + "id": "def-common.UserContentCommonSchema.updatedBy", + "type": "string", + "tags": [], + "label": "updatedBy", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/content-management/table_list_view_common/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/content-management-table-list-view-common", + "id": "def-common.UserContentCommonSchema.createdAt", + "type": "string", + "tags": [], + "label": "createdAt", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/content-management/table_list_view_common/index.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/content-management-table-list-view-common", "id": "def-common.UserContentCommonSchema.createdBy", diff --git a/api_docs/kbn_content_management_table_list_view_common.mdx b/api_docs/kbn_content_management_table_list_view_common.mdx index eaacdb815fed9d..d318908661959d 100644 --- a/api_docs/kbn_content_management_table_list_view_common.mdx +++ b/api_docs/kbn_content_management_table_list_view_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-common title: "@kbn/content-management-table-list-view-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-common'] --- import kbnContentManagementTableListViewCommonObj from './kbn_content_management_table_list_view_common.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 8 | 0 | 8 | 0 | +| 10 | 0 | 10 | 0 | ## Common diff --git a/api_docs/kbn_content_management_table_list_view_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index b204e4dbf83740..0ac0ed64beb77b 100644 --- a/api_docs/kbn_content_management_table_list_view_table.mdx +++ b/api_docs/kbn_content_management_table_list_view_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-table title: "@kbn/content-management-table-list-view-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-table plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_user_profiles.devdocs.json b/api_docs/kbn_content_management_user_profiles.devdocs.json new file mode 100644 index 00000000000000..0107a179f3ac02 --- /dev/null +++ b/api_docs/kbn_content_management_user_profiles.devdocs.json @@ -0,0 +1,622 @@ +{ + "id": "@kbn/content-management-user-profiles", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.ManagedAvatarTip", + "type": "Function", + "tags": [], + "label": "ManagedAvatarTip", + "description": [], + "signature": [ + "({\n entityName = i18n.translate('contentManagement.userProfiles.managedAvatarTip.defaultEntityName', {\n defaultMessage: 'object',\n }),\n}: { entityName?: string | undefined; }) => JSX.Element" + ], + "path": "packages/content-management/user_profiles/src/components/managed_avatar_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.ManagedAvatarTip.$1", + "type": "Object", + "tags": [], + "label": "{\n entityName = i18n.translate('contentManagement.userProfiles.managedAvatarTip.defaultEntityName', {\n defaultMessage: 'object',\n }),\n}", + "description": [], + "path": "packages/content-management/user_profiles/src/components/managed_avatar_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.ManagedAvatarTip.$1.entityName", + "type": "string", + "tags": [], + "label": "entityName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/content-management/user_profiles/src/components/managed_avatar_tip.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.NoCreatorTip", + "type": "Function", + "tags": [], + "label": "NoCreatorTip", + "description": [], + "signature": [ + "(props: { iconType?: ", + "IconType", + " | undefined; }) => JSX.Element" + ], + "path": "packages/content-management/user_profiles/src/components/user_missing_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.NoCreatorTip.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "path": "packages/content-management/user_profiles/src/components/user_missing_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.NoCreatorTip.$1.iconType", + "type": "CompoundType", + "tags": [], + "label": "iconType", + "description": [], + "signature": [ + "IconType", + " | undefined" + ], + "path": "packages/content-management/user_profiles/src/components/user_missing_tip.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.NoUpdaterTip", + "type": "Function", + "tags": [], + "label": "NoUpdaterTip", + "description": [], + "signature": [ + "(props: { iconType?: string | undefined; }) => JSX.Element" + ], + "path": "packages/content-management/user_profiles/src/components/user_missing_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.NoUpdaterTip.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "path": "packages/content-management/user_profiles/src/components/user_missing_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.NoUpdaterTip.$1.iconType", + "type": "string", + "tags": [], + "label": "iconType", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/content-management/user_profiles/src/components/user_missing_tip.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserAvatarTip", + "type": "Function", + "tags": [], + "label": "UserAvatarTip", + "description": [], + "signature": [ + "(props: { uid: string; }) => JSX.Element | null" + ], + "path": "packages/content-management/user_profiles/src/components/user_avatar_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserAvatarTip.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "path": "packages/content-management/user_profiles/src/components/user_avatar_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserAvatarTip.$1.uid", + "type": "string", + "tags": [], + "label": "uid", + "description": [], + "path": "packages/content-management/user_profiles/src/components/user_avatar_tip.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesKibanaProvider", + "type": "Function", + "tags": [], + "label": "UserProfilesKibanaProvider", + "description": [], + "signature": [ + "({ children, core, }: React.PropsWithChildren>) => JSX.Element" + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesKibanaProvider.$1", + "type": "CompoundType", + "tags": [], + "label": "{\n children,\n core,\n}", + "description": [], + "signature": [ + "React.PropsWithChildren>" + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesProvider", + "type": "Function", + "tags": [], + "label": "UserProfilesProvider", + "description": [], + "signature": [ + "({ children, ...services }: React.PropsWithChildren>) => JSX.Element" + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesProvider.$1", + "type": "CompoundType", + "tags": [], + "label": "{\n children,\n ...services\n}", + "description": [], + "signature": [ + "React.PropsWithChildren>" + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.useUserProfile", + "type": "Function", + "tags": [], + "label": "useUserProfile", + "description": [], + "signature": [ + "(uid: string) => ", + "UseQueryResult", + "<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfileData", + "text": "UserProfileData" + }, + ">, unknown>" + ], + "path": "packages/content-management/user_profiles/src/queries.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.useUserProfile.$1", + "type": "string", + "tags": [], + "label": "uid", + "description": [], + "signature": [ + "string" + ], + "path": "packages/content-management/user_profiles/src/queries.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.useUserProfiles", + "type": "Function", + "tags": [], + "label": "useUserProfiles", + "description": [], + "signature": [ + "(uids: string[], opts?: { enabled?: boolean | undefined; } | undefined) => ", + "UseQueryResult", + "<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfileData", + "text": "UserProfileData" + }, + ">[], unknown>" + ], + "path": "packages/content-management/user_profiles/src/queries.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.useUserProfiles.$1", + "type": "Array", + "tags": [], + "label": "uids", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/content-management/user_profiles/src/queries.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.useUserProfiles.$2", + "type": "Object", + "tags": [], + "label": "opts", + "description": [], + "path": "packages/content-management/user_profiles/src/queries.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.useUserProfiles.$2.enabled", + "type": "CompoundType", + "tags": [], + "label": "enabled", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/content-management/user_profiles/src/queries.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.useUserProfilesServices", + "type": "Function", + "tags": [], + "label": "useUserProfilesServices", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/content-management-user-profiles", + "scope": "common", + "docId": "kibKbnContentManagementUserProfilesPluginApi", + "section": "def-common.UserProfilesServices", + "text": "UserProfilesServices" + } + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesKibanaDependencies", + "type": "Interface", + "tags": [], + "label": "UserProfilesKibanaDependencies", + "description": [], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesKibanaDependencies.core", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + "{ userProfile: { bulkGet: (params: ", + { + "pluginId": "@kbn/core-user-profile-browser", + "scope": "common", + "docId": "kibKbnCoreUserProfileBrowserPluginApi", + "section": "def-common.UserProfileBulkGetParams", + "text": "UserProfileBulkGetParams" + }, + ") => Promise<", + { + "pluginId": "@kbn/core-user-profile-common", + "scope": "common", + "docId": "kibKbnCoreUserProfileCommonPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "[]>; }; }" + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesServices", + "type": "Interface", + "tags": [], + "label": "UserProfilesServices", + "description": [], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesServices.bulkGetUserProfiles", + "type": "Function", + "tags": [], + "label": "bulkGetUserProfiles", + "description": [], + "signature": [ + "(uids: string[]) => Promise<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfileData", + "text": "UserProfileData" + }, + ">[]>" + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesServices.bulkGetUserProfiles.$1", + "type": "Array", + "tags": [], + "label": "uids", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesServices.getUserProfile", + "type": "Function", + "tags": [], + "label": "getUserProfile", + "description": [], + "signature": [ + "(uid: string) => Promise<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfile", + "text": "UserProfile" + }, + "<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfileData", + "text": "UserProfileData" + }, + ">>" + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/content-management-user-profiles", + "id": "def-common.UserProfilesServices.getUserProfile.$1", + "type": "string", + "tags": [], + "label": "uid", + "description": [], + "signature": [ + "string" + ], + "path": "packages/content-management/user_profiles/src/services.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_content_management_user_profiles.mdx b/api_docs/kbn_content_management_user_profiles.mdx new file mode 100644 index 00000000000000..8c7fdd49f0c664 --- /dev/null +++ b/api_docs/kbn_content_management_user_profiles.mdx @@ -0,0 +1,33 @@ +--- +#### +#### 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. +#### +id: kibKbnContentManagementUserProfilesPluginApi +slug: /kibana-dev-docs/api/kbn-content-management-user-profiles +title: "@kbn/content-management-user-profiles" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/content-management-user-profiles plugin +date: 2024-06-19 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-user-profiles'] +--- +import kbnContentManagementUserProfilesObj from './kbn_content_management_user_profiles.devdocs.json'; + + + +Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 30 | 0 | 30 | 0 | + +## Common + +### Functions + + +### Interfaces + + diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 95d831172342ad..5e36fe54ede763 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.devdocs.json b/api_docs/kbn_core_analytics_browser.devdocs.json index 1f9e8beb3c1608..7f19ef23a3e2da 100644 --- a/api_docs/kbn_core_analytics_browser.devdocs.json +++ b/api_docs/kbn_core_analytics_browser.devdocs.json @@ -20,36 +20,2867 @@ "classes": [], "functions": [], "interfaces": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.AnalyticsClientInitContext", + "type": "Interface", + "tags": [], + "label": "AnalyticsClientInitContext", + "description": [ + "\nGeneral settings of the analytics client" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.AnalyticsClientInitContext.isDev", + "type": "boolean", + "tags": [], + "label": "isDev", + "description": [ + "\nBoolean indicating if it's running in developer mode." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.AnalyticsClientInitContext.sendTo", + "type": "CompoundType", + "tags": [], + "label": "sendTo", + "description": [ + "\nSpecify if the shippers should send their data to the production or staging environments." + ], + "signature": [ + "\"production\" | \"staging\"" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.AnalyticsClientInitContext.logger", + "type": "Object", + "tags": [], + "label": "logger", + "description": [ + "\nApplication-provided logger." + ], + "signature": [ + { + "pluginId": "@kbn/logging", + "scope": "common", + "docId": "kibKbnLoggingPluginApi", + "section": "def-common.Logger", + "text": "Logger" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ContextProviderOpts", + "type": "Interface", + "tags": [], + "label": "ContextProviderOpts", + "description": [ + "\nDefinition of a context provider" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ContextProviderOpts", + "text": "ContextProviderOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ContextProviderOpts.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nThe name of the provider." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ContextProviderOpts.context$", + "type": "Object", + "tags": [], + "label": "context$", + "description": [ + "\nObservable that emits the custom context." + ], + "signature": [ + "Observable", + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ContextProviderOpts.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [ + "\nSchema declaring and documenting the expected output in the context$\n" + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.Event", + "type": "Interface", + "tags": [], + "label": "Event", + "description": [ + "\nDefinition of the full event structure" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.Event.timestamp", + "type": "string", + "tags": [], + "label": "timestamp", + "description": [ + "\nThe time the event was generated in ISO format." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.Event.event_type", + "type": "string", + "tags": [], + "label": "event_type", + "description": [ + "\nThe event type." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.Event.properties", + "type": "Uncategorized", + "tags": [], + "label": "properties", + "description": [ + "\nThe specific properties of the event type." + ], + "signature": [ + "Properties" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.Event.context", + "type": "Object", + "tags": [], + "label": "context", + "description": [ + "\nThe {@link EventContext} enriched during the processing pipeline." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + } + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext", + "type": "Interface", + "tags": [], + "label": "EventContext", + "description": [ + "\nDefinition of the context that can be appended to the events through the {@link IAnalyticsClient.registerContextProvider}." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.cluster_uuid", + "type": "string", + "tags": [], + "label": "cluster_uuid", + "description": [ + "\nThe UUID of the cluster" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.cluster_name", + "type": "string", + "tags": [], + "label": "cluster_name", + "description": [ + "\nThe name of the cluster." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.license_id", + "type": "string", + "tags": [], + "label": "license_id", + "description": [ + "\nThe license ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.userId", + "type": "string", + "tags": [], + "label": "userId", + "description": [ + "\nThe unique user ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.cloudId", + "type": "string", + "tags": [], + "label": "cloudId", + "description": [ + "\nThe Cloud ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.isElasticCloudUser", + "type": "CompoundType", + "tags": [], + "label": "isElasticCloudUser", + "description": [ + "\n`true` if the user is logged in via the Elastic Cloud authentication provider." + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.version", + "type": "string", + "tags": [], + "label": "version", + "description": [ + "\nThe product's version." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.pageName", + "type": "string", + "tags": [], + "label": "pageName", + "description": [ + "\nThe name of the current page." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.applicationId", + "type": "string", + "tags": [], + "label": "applicationId", + "description": [ + "\nThe current application ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.entityId", + "type": "string", + "tags": [], + "label": "entityId", + "description": [ + "\nThe current entity ID (dashboard ID, visualization ID, etc.)." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventContext.Unnamed", + "type": "IndexSignature", + "tags": [], + "label": "[key: string]: unknown", + "description": [ + "\nAdditional keys are allowed." + ], + "signature": [ + "[key: string]: unknown" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventTypeOpts", + "type": "Interface", + "tags": [], + "label": "EventTypeOpts", + "description": [ + "\nDefinition of an Event Type." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventTypeOpts", + "text": "EventTypeOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventTypeOpts.eventType", + "type": "string", + "tags": [], + "label": "eventType", + "description": [ + "\nThe event type's unique name." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventTypeOpts.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [ + "\nSchema declaring and documenting the expected structure of this event type.\n" + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient", + "type": "Interface", + "tags": [], + "label": "IAnalyticsClient", + "description": [ + "\nAnalytics client's public APIs" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.reportEvent", + "type": "Function", + "tags": [ + "track-adoption" + ], + "label": "reportEvent", + "description": [ + "\nReports a telemetry event." + ], + "signature": [ + "(eventType: string, eventData: EventTypeData) => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": true, + "references": [ + { + "plugin": "@kbn/core-notifications-browser-internal", + "path": "packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_reporter.ts" + }, + { + "plugin": "@kbn/core-notifications-browser-internal", + "path": "packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_reporter.ts" + }, + { + "plugin": "@kbn/ebt-tools", + "path": "packages/kbn-ebt-tools/src/performance_metric_events/helpers.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-root-server-internal", + "path": "packages/core/root/core-root-server-internal/src/events/kibana_started.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/analytics/types.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/analytics/analytics_service.ts" + }, + { + "plugin": "observabilityAIAssistant", + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/server/utils/recall/recall_and_score.ts" + }, + { + "plugin": "observabilityAIAssistant", + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" + }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" + }, + { + "plugin": "globalSearchBar", + "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" + }, + { + "plugin": "globalSearchBar", + "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts" + }, + { + "plugin": "reporting", + "path": "x-pack/plugins/reporting/server/usage/event_tracker.ts" + }, + { + "plugin": "searchPlayground", + "path": "x-pack/plugins/search_playground/server/routes.ts" + }, + { + "plugin": "securitySolutionServerless", + "path": "x-pack/plugins/security_solution_serverless/server/task_manager/nlp_cleanup_task/nlp_cleanup_task.ts" + }, + { + "plugin": "securitySolutionServerless", + "path": "x-pack/plugins/security_solution_serverless/server/task_manager/nlp_cleanup_task/nlp_cleanup_task.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "observabilityLogsExplorer", + "path": "x-pack/plugins/observability_solution/observability_logs_explorer/public/state_machines/observability_logs_explorer/src/telemetry_events.ts" + }, + { + "plugin": "observabilityOnboarding", + "path": "x-pack/plugins/observability_solution/observability_onboarding/public/hooks/use_flow_progress_telemetry.ts" + }, + { + "plugin": "observabilityOnboarding", + "path": "x-pack/plugins/observability_solution/observability_onboarding/public/application/app.tsx" + }, + { + "plugin": "observabilityAIAssistant", + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/service/create_chat_service.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-mocks", + "path": "packages/core/analytics/core-analytics-browser-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-mocks", + "path": "packages/core/analytics/core-analytics-browser-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/analytics/analytics.stub.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts" + } + ], + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.reportEvent.$1", + "type": "string", + "tags": [], + "label": "eventType", + "description": [ + "The event type registered via the `registerEventType` API." + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.reportEvent.$2", + "type": "Uncategorized", + "tags": [], + "label": "eventData", + "description": [ + "The properties matching the schema declared in the `registerEventType` API." + ], + "signature": [ + "EventTypeData" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.registerEventType", + "type": "Function", + "tags": [], + "label": "registerEventType", + "description": [ + "\nRegisters the event type that will be emitted via the reportEvent API." + ], + "signature": [ + "(eventTypeOps: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventTypeOpts", + "text": "EventTypeOpts" + }, + ") => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.registerEventType.$1", + "type": "Object", + "tags": [], + "label": "eventTypeOps", + "description": [ + "The definition of the event type {@link EventTypeOpts }." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventTypeOpts", + "text": "EventTypeOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.registerShipper", + "type": "Function", + "tags": [], + "label": "registerShipper", + "description": [ + "\nSet up the shipper that will be used to report the telemetry events." + ], + "signature": [ + "(Shipper: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ShipperClassConstructor", + "text": "ShipperClassConstructor" + }, + ", shipperConfig: ShipperConfig, opts?: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.RegisterShipperOpts", + "text": "RegisterShipperOpts" + }, + " | undefined) => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.registerShipper.$1", + "type": "Object", + "tags": [], + "label": "Shipper", + "description": [ + "The {@link IShipper } class to instantiate the shipper." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ShipperClassConstructor", + "text": "ShipperClassConstructor" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.registerShipper.$2", + "type": "Uncategorized", + "tags": [], + "label": "shipperConfig", + "description": [ + "The config specific to the Shipper to instantiate." + ], + "signature": [ + "ShipperConfig" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.registerShipper.$3", + "type": "Object", + "tags": [], + "label": "opts", + "description": [ + "Additional options to register the shipper {@link RegisterShipperOpts }." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.RegisterShipperOpts", + "text": "RegisterShipperOpts" + }, + " | undefined" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nUsed to control the user's consent to report the data.\nIn the advanced mode, it allows to \"cherry-pick\" which events and shippers are enabled/disabled." + ], + "signature": [ + "(optInConfig: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.OptInConfig", + "text": "OptInConfig" + }, + ") => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.optIn.$1", + "type": "Object", + "tags": [], + "label": "optInConfig", + "description": [ + "{@link OptInConfig }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.OptInConfig", + "text": "OptInConfig" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.registerContextProvider", + "type": "Function", + "tags": [ + "track-adoption" + ], + "label": "registerContextProvider", + "description": [ + "\nRegisters the context provider to enrich any reported events." + ], + "signature": [ + "(contextProviderOpts: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ContextProviderOpts", + "text": "ContextProviderOpts" + }, + ") => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": true, + "references": [ + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.ts" + }, + { + "plugin": "@kbn/core-elasticsearch-server-internal", + "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/register_analytics_context_provider.ts" + }, + { + "plugin": "@kbn/core-environment-server-internal", + "path": "packages/core/environment/core-environment-server-internal/src/environment_service.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "cloud", + "path": "x-pack/plugins/cloud/common/register_cloud_deployment_id_analytics_context.ts" + }, + { + "plugin": "licensing", + "path": "x-pack/plugins/licensing/common/register_analytics_context_provider.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.ts" + }, + { + "plugin": "telemetry", + "path": "src/plugins/telemetry/server/plugin.ts" + }, + { + "plugin": "telemetry", + "path": "src/plugins/telemetry/public/plugin.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-mocks", + "path": "packages/core/analytics/core-analytics-browser-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.test.ts" + }, + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-elasticsearch-server-internal", + "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.ts" + } + ], + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.registerContextProvider.$1", + "type": "Object", + "tags": [], + "label": "contextProviderOpts", + "description": [ + "{@link ContextProviderOpts }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ContextProviderOpts", + "text": "ContextProviderOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.removeContextProvider", + "type": "Function", + "tags": [], + "label": "removeContextProvider", + "description": [ + "\nRemoves the context provider and stop enriching the events from its context." + ], + "signature": [ + "(contextProviderName: string) => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.removeContextProvider.$1", + "type": "string", + "tags": [], + "label": "contextProviderName", + "description": [ + "The name of the context provider to remove." + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.telemetryCounter$", + "type": "Object", + "tags": [], + "label": "telemetryCounter$", + "description": [ + "\nObservable to emit the stats of the processed events." + ], + "signature": [ + "Observable", + "<", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.TelemetryCounter", + "text": "TelemetryCounter" + }, + ">" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nForces all shippers to send all their enqueued events and fulfills the returned promise." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IAnalyticsClient.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nStops the client. Flushing any pending events in the process." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper", + "type": "Interface", + "tags": [], + "label": "IShipper", + "description": [ + "\nBasic structure of a Shipper" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper.reportEvents", + "type": "Function", + "tags": [], + "label": "reportEvents", + "description": [ + "\nAdapts and ships the event to the persisting/analytics solution." + ], + "signature": [ + "(events: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]) => void" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper.reportEvents.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [ + "batched events {@link Event }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nStops/restarts the shipping mechanism based on the value of isOptedIn" + ], + "signature": [ + "(isOptedIn: boolean) => void" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper.optIn.$1", + "type": "boolean", + "tags": [], + "label": "isOptedIn", + "description": [ + "`true` for resume sending events. `false` to stop." + ], + "signature": [ + "boolean" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper.extendContext", + "type": "Function", + "tags": [], + "label": "extendContext", + "description": [ + "\nPerform any necessary calls to the persisting/analytics solution to set the event's context." + ], + "signature": [ + "((newContext: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + }, + ") => void) | undefined" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper.extendContext.$1", + "type": "Object", + "tags": [], + "label": "newContext", + "description": [ + "The full new context to set {@link EventContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + } + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper.telemetryCounter$", + "type": "Object", + "tags": [], + "label": "telemetryCounter$", + "description": [ + "\nObservable to emit the stats of the processed events." + ], + "signature": [ + "Observable", + "<", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.TelemetryCounter", + "text": "TelemetryCounter" + }, + "> | undefined" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nSends all the enqueued events and fulfills the returned promise." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.IShipper.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nShutdown the shipper." + ], + "signature": [ + "() => void" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-analytics-browser", "id": "def-common.KbnAnalyticsWindowApi", "type": "Interface", "tags": [], - "label": "KbnAnalyticsWindowApi", + "label": "KbnAnalyticsWindowApi", + "description": [ + "\nAPI exposed through `window.__kbnAnalytics`" + ], + "path": "packages/core/analytics/core-analytics-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.KbnAnalyticsWindowApi.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nReturns a promise that resolves when all the events in the queue have been sent." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/core/analytics/core-analytics-browser/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.OptInConfig", + "type": "Interface", + "tags": [], + "label": "OptInConfig", + "description": [ + "\nOptions for the optIn API" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.OptInConfig.global", + "type": "Object", + "tags": [], + "label": "global", + "description": [ + "\nControls the global enabled/disabled behaviour of the client and shippers." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.OptInConfigPerType", + "text": "OptInConfigPerType" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.OptInConfig.event_types", + "type": "Object", + "tags": [], + "label": "event_types", + "description": [ + "\nControls if an event type should be disabled for a specific type of shipper." + ], + "signature": [ + "Record | undefined" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.OptInConfigPerType", + "type": "Interface", + "tags": [], + "label": "OptInConfigPerType", + "description": [ + "\nSets whether a type of event is enabled/disabled globally or per shipper." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.OptInConfigPerType.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [ + "\nThe event type is globally enabled." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.OptInConfigPerType.shippers", + "type": "Object", + "tags": [], + "label": "shippers", + "description": [ + "\nControls if an event type should be disabled for a specific type of shipper." + ], + "signature": [ + "Record | undefined" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.RegisterShipperOpts", + "type": "Interface", + "tags": [], + "label": "RegisterShipperOpts", + "description": [ + "\nOptional options to register a shipper" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaArray", + "type": "Interface", + "tags": [], + "label": "SchemaArray", + "description": [ + "\nSchema to represent an array" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " extends ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMeta", + "text": "SchemaMeta" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaArray.type", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "The type must be an array" + ], + "signature": [ + "\"array\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaArray.items", + "type": "CompoundType", + "tags": [], + "label": "items", + "description": [ + "The schema of the items in the array is defined in the `items` property" + ], + "signature": [ + "{ type: \"pass_through\"; _meta: { description: string; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + "; } | (unknown extends Value ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends (infer U)[] | readonly (infer U)[] ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " : NonNullable extends Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends object ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + ")" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaChildValue", + "type": "Interface", + "tags": [], + "label": "SchemaChildValue", + "description": [ + "\nSchema to define a primitive value" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaChildValue.type", + "type": "Uncategorized", + "tags": [], + "label": "type", + "description": [ + "The type of the value" + ], + "signature": [ + "NonNullable extends string | Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaStringTypes", + "text": "AllowedSchemaStringTypes" + }, + " : NonNullable extends number ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaNumberTypes", + "text": "AllowedSchemaNumberTypes" + }, + " : NonNullable extends boolean ? \"boolean\" : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaTypes", + "text": "AllowedSchemaTypes" + } + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaChildValue._meta", + "type": "CompoundType", + "tags": [], + "label": "_meta", + "description": [ + "Meta properties of the value: description and is optional" + ], + "signature": [ + "{ description: string; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaMeta", + "type": "Interface", + "tags": [], + "label": "SchemaMeta", + "description": [ + "\nSchema meta with optional description" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMeta", + "text": "SchemaMeta" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaMeta._meta", + "type": "CompoundType", + "tags": [], + "label": "_meta", + "description": [ + "Meta properties of the pass through: description and is optional" + ], + "signature": [ + "({ description?: string | undefined; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + ") | undefined" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaObject", + "type": "Interface", + "tags": [], + "label": "SchemaObject", + "description": [ + "\nSchema to represent an object" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " extends ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMeta", + "text": "SchemaMeta" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaObject.properties", + "type": "Object", + "tags": [], + "label": "properties", + "description": [ + "\nThe schemas of the keys of the object are defined in the `properties` object." + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ShipperClassConstructor", + "type": "Interface", + "tags": [], + "label": "ShipperClassConstructor", "description": [ - "\nAPI exposed through `window.__kbnAnalytics`" + "\nConstructor of a {@link IShipper}" ], - "path": "packages/core/analytics/core-analytics-browser/src/types.ts", + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ShipperClassConstructor", + "text": "ShipperClassConstructor" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/core-analytics-browser", - "id": "def-common.KbnAnalyticsWindowApi.flush", + "id": "def-common.ShipperClassConstructor.shipperName", + "type": "string", + "tags": [], + "label": "shipperName", + "description": [ + "\nThe shipper's unique name" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ShipperClassConstructor.new", "type": "Function", "tags": [], - "label": "flush", + "label": "new", "description": [ - "\nReturns a promise that resolves when all the events in the queue have been sent." + "\nThe constructor" ], "signature": [ - "() => Promise" + "any" ], - "path": "packages/core/analytics/core-analytics-browser/src/types.ts", + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", "deprecated": false, "trackAdoption": false, - "returnComment": [], - "children": [] + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ShipperClassConstructor.new.$1", + "type": "Uncategorized", + "tags": [], + "label": "config", + "description": [ + "The shipper's custom config" + ], + "signature": [ + "Config" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ShipperClassConstructor.new.$2", + "type": "Object", + "tags": [], + "label": "initContext", + "description": [ + "Common context {@link AnalyticsClientInitContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AnalyticsClientInitContext", + "text": "AnalyticsClientInitContext" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.TelemetryCounter", + "type": "Interface", + "tags": [], + "label": "TelemetryCounter", + "description": [ + "\nShape of the events emitted by the telemetryCounter$ observable" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.TelemetryCounter.type", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [ + "\n{@link TelemetryCounterType}" + ], + "signature": [ + "\"succeeded\" | \"failed\" | \"enqueued\" | \"sent_to_shipper\" | \"dropped\"" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.TelemetryCounter.source", + "type": "string", + "tags": [], + "label": "source", + "description": [ + "\nWho emitted the event? It can be \"client\" or the name of the shipper." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.TelemetryCounter.event_type", + "type": "string", + "tags": [], + "label": "event_type", + "description": [ + "\nThe event type the success/failure/drop event refers to." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.TelemetryCounter.code", + "type": "string", + "tags": [], + "label": "code", + "description": [ + "\nCode to provide additional information about the success or failure. Examples are 200/400/504/ValidationError/UnknownError" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.TelemetryCounter.count", + "type": "number", + "tags": [], + "label": "count", + "description": [ + "\nThe number of events that this counter refers to." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -57,6 +2888,74 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.AllowedSchemaBooleanTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaBooleanTypes", + "description": [ + "Types matching boolean values" + ], + "signature": [ + "\"boolean\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.AllowedSchemaNumberTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaNumberTypes", + "description": [ + "Types matching number values" + ], + "signature": [ + "\"date\" | \"integer\" | \"long\" | \"short\" | \"byte\" | \"float\" | \"double\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.AllowedSchemaStringTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaStringTypes", + "description": [ + "Types matching string values" + ], + "signature": [ + "\"keyword\" | \"text\" | \"date\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.AllowedSchemaTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaTypes", + "description": [ + "\nPossible type values in the schema" + ], + "signature": [ + "\"boolean\" | \"keyword\" | \"text\" | \"date\" | \"integer\" | \"long\" | \"short\" | \"byte\" | \"float\" | \"double\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-analytics-browser", "id": "def-common.AnalyticsServiceSetup", @@ -69,9 +2968,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -79,49 +2978,49 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, ">; registerEventType: (eventTypeOps: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.EventTypeOpts", "text": "EventTypeOpts" }, ") => void; registerShipper: (Shipper: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ShipperClassConstructor", "text": "ShipperClassConstructor" }, ", shipperConfig: ShipperConfig, opts?: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.RegisterShipperOpts", "text": "RegisterShipperOpts" }, " | undefined) => void; registerContextProvider: (contextProviderOpts: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ContextProviderOpts", "text": "ContextProviderOpts" }, @@ -144,9 +3043,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -154,9 +3053,9 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, @@ -166,6 +3065,237 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ContextProviderName", + "type": "Type", + "tags": [], + "label": "ContextProviderName", + "description": [ + "\nContextProviderName used for indexed structures. Only used to improve the readability of the types" + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.EventType", + "type": "Type", + "tags": [], + "label": "EventType", + "description": [ + "\nEvent Type used for indexed structures. Only used to improve the readability of the types" + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.PossibleSchemaTypes", + "type": "Type", + "tags": [], + "label": "PossibleSchemaTypes", + "description": [ + "\nHelper to ensure the declared types match the schema types" + ], + "signature": [ + "Value extends string | Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaStringTypes", + "text": "AllowedSchemaStringTypes" + }, + " : Value extends number ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaNumberTypes", + "text": "AllowedSchemaNumberTypes" + }, + " : Value extends boolean ? \"boolean\" : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaTypes", + "text": "AllowedSchemaTypes" + } + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.RootSchema", + "type": "Type", + "tags": [], + "label": "RootSchema", + "description": [ + "\nSchema definition to match the structure of the properties provided.\n" + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaMetaOptional", + "type": "Type", + "tags": [], + "label": "SchemaMetaOptional", + "description": [ + "\nEnforces { optional: true } if the value can be undefined" + ], + "signature": [ + "unknown extends Value ? { optional?: boolean | undefined; } : undefined extends Value ? { optional: true; } : { optional?: false | undefined; }" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.SchemaValue", + "type": "Type", + "tags": [], + "label": "SchemaValue", + "description": [ + "\nType that defines all the possible values that the Schema accepts.\nThese types definitions are helping to identify earlier the possible missing `properties` nesting when\nmanually defining the schemas." + ], + "signature": [ + "{ type: \"pass_through\"; _meta: { description: string; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + "; } | (unknown extends Value ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends (infer U)[] | readonly (infer U)[] ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " : NonNullable extends Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends object ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + ")" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.ShipperName", + "type": "Type", + "tags": [], + "label": "ShipperName", + "description": [ + "\nShipper Name used for indexed structures. Only used to improve the readability of the types" + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-browser", + "id": "def-common.TelemetryCounterType", + "type": "Type", + "tags": [], + "label": "TelemetryCounterType", + "description": [ + "\nIndicates if the event contains data about succeeded, failed or dropped events:\n- enqueued: The event was accepted and will be sent to the shippers when they become available (and opt-in === true).\n- sent_to_shipper: The event was sent to at least one shipper.\n- succeeded: The event was successfully sent by the shipper.\n- failed: There was an error when processing/shipping the event. Refer to the Telemetry Counter's code for the reason.\n- dropped: The event was dropped from the queue. Refer to the Telemetry Counter's code for the reason." + ], + "signature": [ + "\"succeeded\" | \"failed\" | \"enqueued\" | \"sent_to_shipper\" | \"dropped\"" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 5e8fb7e681138f..c8ff98d0fd1d83 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 4 | 0 | 0 | 0 | +| 101 | 0 | 0 | 0 | ## Common diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index 79058a9a104e2d..a8a42992594aff 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 6c6b2b592bb48e..f6911a5bcdb2b6 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.devdocs.json b/api_docs/kbn_core_analytics_server.devdocs.json index 9f116d542418f2..5c4760eb2c883f 100644 --- a/api_docs/kbn_core_analytics_server.devdocs.json +++ b/api_docs/kbn_core_analytics_server.devdocs.json @@ -19,9 +19,2909 @@ "common": { "classes": [], "functions": [], - "interfaces": [], + "interfaces": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.AnalyticsClientInitContext", + "type": "Interface", + "tags": [], + "label": "AnalyticsClientInitContext", + "description": [ + "\nGeneral settings of the analytics client" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.AnalyticsClientInitContext.isDev", + "type": "boolean", + "tags": [], + "label": "isDev", + "description": [ + "\nBoolean indicating if it's running in developer mode." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.AnalyticsClientInitContext.sendTo", + "type": "CompoundType", + "tags": [], + "label": "sendTo", + "description": [ + "\nSpecify if the shippers should send their data to the production or staging environments." + ], + "signature": [ + "\"production\" | \"staging\"" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.AnalyticsClientInitContext.logger", + "type": "Object", + "tags": [], + "label": "logger", + "description": [ + "\nApplication-provided logger." + ], + "signature": [ + { + "pluginId": "@kbn/logging", + "scope": "common", + "docId": "kibKbnLoggingPluginApi", + "section": "def-common.Logger", + "text": "Logger" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ContextProviderOpts", + "type": "Interface", + "tags": [], + "label": "ContextProviderOpts", + "description": [ + "\nDefinition of a context provider" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ContextProviderOpts", + "text": "ContextProviderOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ContextProviderOpts.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nThe name of the provider." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ContextProviderOpts.context$", + "type": "Object", + "tags": [], + "label": "context$", + "description": [ + "\nObservable that emits the custom context." + ], + "signature": [ + "Observable", + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ContextProviderOpts.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [ + "\nSchema declaring and documenting the expected output in the context$\n" + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.Event", + "type": "Interface", + "tags": [], + "label": "Event", + "description": [ + "\nDefinition of the full event structure" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.Event.timestamp", + "type": "string", + "tags": [], + "label": "timestamp", + "description": [ + "\nThe time the event was generated in ISO format." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.Event.event_type", + "type": "string", + "tags": [], + "label": "event_type", + "description": [ + "\nThe event type." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.Event.properties", + "type": "Uncategorized", + "tags": [], + "label": "properties", + "description": [ + "\nThe specific properties of the event type." + ], + "signature": [ + "Properties" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.Event.context", + "type": "Object", + "tags": [], + "label": "context", + "description": [ + "\nThe {@link EventContext} enriched during the processing pipeline." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + } + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext", + "type": "Interface", + "tags": [], + "label": "EventContext", + "description": [ + "\nDefinition of the context that can be appended to the events through the {@link IAnalyticsClient.registerContextProvider}." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.cluster_uuid", + "type": "string", + "tags": [], + "label": "cluster_uuid", + "description": [ + "\nThe UUID of the cluster" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.cluster_name", + "type": "string", + "tags": [], + "label": "cluster_name", + "description": [ + "\nThe name of the cluster." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.license_id", + "type": "string", + "tags": [], + "label": "license_id", + "description": [ + "\nThe license ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.userId", + "type": "string", + "tags": [], + "label": "userId", + "description": [ + "\nThe unique user ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.cloudId", + "type": "string", + "tags": [], + "label": "cloudId", + "description": [ + "\nThe Cloud ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.isElasticCloudUser", + "type": "CompoundType", + "tags": [], + "label": "isElasticCloudUser", + "description": [ + "\n`true` if the user is logged in via the Elastic Cloud authentication provider." + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.version", + "type": "string", + "tags": [], + "label": "version", + "description": [ + "\nThe product's version." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.pageName", + "type": "string", + "tags": [], + "label": "pageName", + "description": [ + "\nThe name of the current page." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.applicationId", + "type": "string", + "tags": [], + "label": "applicationId", + "description": [ + "\nThe current application ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.entityId", + "type": "string", + "tags": [], + "label": "entityId", + "description": [ + "\nThe current entity ID (dashboard ID, visualization ID, etc.)." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventContext.Unnamed", + "type": "IndexSignature", + "tags": [], + "label": "[key: string]: unknown", + "description": [ + "\nAdditional keys are allowed." + ], + "signature": [ + "[key: string]: unknown" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventTypeOpts", + "type": "Interface", + "tags": [], + "label": "EventTypeOpts", + "description": [ + "\nDefinition of an Event Type." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventTypeOpts", + "text": "EventTypeOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventTypeOpts.eventType", + "type": "string", + "tags": [], + "label": "eventType", + "description": [ + "\nThe event type's unique name." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventTypeOpts.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [ + "\nSchema declaring and documenting the expected structure of this event type.\n" + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient", + "type": "Interface", + "tags": [], + "label": "IAnalyticsClient", + "description": [ + "\nAnalytics client's public APIs" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.reportEvent", + "type": "Function", + "tags": [ + "track-adoption" + ], + "label": "reportEvent", + "description": [ + "\nReports a telemetry event." + ], + "signature": [ + "(eventType: string, eventData: EventTypeData) => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": true, + "references": [ + { + "plugin": "@kbn/core-notifications-browser-internal", + "path": "packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_reporter.ts" + }, + { + "plugin": "@kbn/core-notifications-browser-internal", + "path": "packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_reporter.ts" + }, + { + "plugin": "@kbn/ebt-tools", + "path": "packages/kbn-ebt-tools/src/performance_metric_events/helpers.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-root-server-internal", + "path": "packages/core/root/core-root-server-internal/src/events/kibana_started.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/analytics/types.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/analytics/analytics_service.ts" + }, + { + "plugin": "observabilityAIAssistant", + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/server/utils/recall/recall_and_score.ts" + }, + { + "plugin": "observabilityAIAssistant", + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" + }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" + }, + { + "plugin": "globalSearchBar", + "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" + }, + { + "plugin": "globalSearchBar", + "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts" + }, + { + "plugin": "reporting", + "path": "x-pack/plugins/reporting/server/usage/event_tracker.ts" + }, + { + "plugin": "searchPlayground", + "path": "x-pack/plugins/search_playground/server/routes.ts" + }, + { + "plugin": "securitySolutionServerless", + "path": "x-pack/plugins/security_solution_serverless/server/task_manager/nlp_cleanup_task/nlp_cleanup_task.ts" + }, + { + "plugin": "securitySolutionServerless", + "path": "x-pack/plugins/security_solution_serverless/server/task_manager/nlp_cleanup_task/nlp_cleanup_task.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "observabilityLogsExplorer", + "path": "x-pack/plugins/observability_solution/observability_logs_explorer/public/state_machines/observability_logs_explorer/src/telemetry_events.ts" + }, + { + "plugin": "observabilityOnboarding", + "path": "x-pack/plugins/observability_solution/observability_onboarding/public/hooks/use_flow_progress_telemetry.ts" + }, + { + "plugin": "observabilityOnboarding", + "path": "x-pack/plugins/observability_solution/observability_onboarding/public/application/app.tsx" + }, + { + "plugin": "observabilityAIAssistant", + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/service/create_chat_service.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-mocks", + "path": "packages/core/analytics/core-analytics-browser-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-mocks", + "path": "packages/core/analytics/core-analytics-browser-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/analytics/analytics.stub.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts" + } + ], + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.reportEvent.$1", + "type": "string", + "tags": [], + "label": "eventType", + "description": [ + "The event type registered via the `registerEventType` API." + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.reportEvent.$2", + "type": "Uncategorized", + "tags": [], + "label": "eventData", + "description": [ + "The properties matching the schema declared in the `registerEventType` API." + ], + "signature": [ + "EventTypeData" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.registerEventType", + "type": "Function", + "tags": [], + "label": "registerEventType", + "description": [ + "\nRegisters the event type that will be emitted via the reportEvent API." + ], + "signature": [ + "(eventTypeOps: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventTypeOpts", + "text": "EventTypeOpts" + }, + ") => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.registerEventType.$1", + "type": "Object", + "tags": [], + "label": "eventTypeOps", + "description": [ + "The definition of the event type {@link EventTypeOpts }." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventTypeOpts", + "text": "EventTypeOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.registerShipper", + "type": "Function", + "tags": [], + "label": "registerShipper", + "description": [ + "\nSet up the shipper that will be used to report the telemetry events." + ], + "signature": [ + "(Shipper: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ShipperClassConstructor", + "text": "ShipperClassConstructor" + }, + ", shipperConfig: ShipperConfig, opts?: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.RegisterShipperOpts", + "text": "RegisterShipperOpts" + }, + " | undefined) => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.registerShipper.$1", + "type": "Object", + "tags": [], + "label": "Shipper", + "description": [ + "The {@link IShipper } class to instantiate the shipper." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ShipperClassConstructor", + "text": "ShipperClassConstructor" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.registerShipper.$2", + "type": "Uncategorized", + "tags": [], + "label": "shipperConfig", + "description": [ + "The config specific to the Shipper to instantiate." + ], + "signature": [ + "ShipperConfig" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.registerShipper.$3", + "type": "Object", + "tags": [], + "label": "opts", + "description": [ + "Additional options to register the shipper {@link RegisterShipperOpts }." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.RegisterShipperOpts", + "text": "RegisterShipperOpts" + }, + " | undefined" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nUsed to control the user's consent to report the data.\nIn the advanced mode, it allows to \"cherry-pick\" which events and shippers are enabled/disabled." + ], + "signature": [ + "(optInConfig: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.OptInConfig", + "text": "OptInConfig" + }, + ") => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.optIn.$1", + "type": "Object", + "tags": [], + "label": "optInConfig", + "description": [ + "{@link OptInConfig }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.OptInConfig", + "text": "OptInConfig" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.registerContextProvider", + "type": "Function", + "tags": [ + "track-adoption" + ], + "label": "registerContextProvider", + "description": [ + "\nRegisters the context provider to enrich any reported events." + ], + "signature": [ + "(contextProviderOpts: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ContextProviderOpts", + "text": "ContextProviderOpts" + }, + ") => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": true, + "references": [ + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.ts" + }, + { + "plugin": "@kbn/core-elasticsearch-server-internal", + "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/register_analytics_context_provider.ts" + }, + { + "plugin": "@kbn/core-environment-server-internal", + "path": "packages/core/environment/core-environment-server-internal/src/environment_service.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "cloud", + "path": "x-pack/plugins/cloud/common/register_cloud_deployment_id_analytics_context.ts" + }, + { + "plugin": "licensing", + "path": "x-pack/plugins/licensing/common/register_analytics_context_provider.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.ts" + }, + { + "plugin": "telemetry", + "path": "src/plugins/telemetry/server/plugin.ts" + }, + { + "plugin": "telemetry", + "path": "src/plugins/telemetry/public/plugin.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/analytics_client.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-mocks", + "path": "packages/core/analytics/core-analytics-browser-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.test.ts" + }, + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-elasticsearch-server-internal", + "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/ebt", + "path": "packages/analytics/ebt/client/src/analytics_client/mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.ts" + } + ], + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.registerContextProvider.$1", + "type": "Object", + "tags": [], + "label": "contextProviderOpts", + "description": [ + "{@link ContextProviderOpts }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ContextProviderOpts", + "text": "ContextProviderOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.removeContextProvider", + "type": "Function", + "tags": [], + "label": "removeContextProvider", + "description": [ + "\nRemoves the context provider and stop enriching the events from its context." + ], + "signature": [ + "(contextProviderName: string) => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.removeContextProvider.$1", + "type": "string", + "tags": [], + "label": "contextProviderName", + "description": [ + "The name of the context provider to remove." + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.telemetryCounter$", + "type": "Object", + "tags": [], + "label": "telemetryCounter$", + "description": [ + "\nObservable to emit the stats of the processed events." + ], + "signature": [ + "Observable", + "<", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.TelemetryCounter", + "text": "TelemetryCounter" + }, + ">" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nForces all shippers to send all their enqueued events and fulfills the returned promise." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IAnalyticsClient.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nStops the client. Flushing any pending events in the process." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper", + "type": "Interface", + "tags": [], + "label": "IShipper", + "description": [ + "\nBasic structure of a Shipper" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper.reportEvents", + "type": "Function", + "tags": [], + "label": "reportEvents", + "description": [ + "\nAdapts and ships the event to the persisting/analytics solution." + ], + "signature": [ + "(events: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]) => void" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper.reportEvents.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [ + "batched events {@link Event }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nStops/restarts the shipping mechanism based on the value of isOptedIn" + ], + "signature": [ + "(isOptedIn: boolean) => void" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper.optIn.$1", + "type": "boolean", + "tags": [], + "label": "isOptedIn", + "description": [ + "`true` for resume sending events. `false` to stop." + ], + "signature": [ + "boolean" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper.extendContext", + "type": "Function", + "tags": [], + "label": "extendContext", + "description": [ + "\nPerform any necessary calls to the persisting/analytics solution to set the event's context." + ], + "signature": [ + "((newContext: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + }, + ") => void) | undefined" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper.extendContext.$1", + "type": "Object", + "tags": [], + "label": "newContext", + "description": [ + "The full new context to set {@link EventContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + } + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper.telemetryCounter$", + "type": "Object", + "tags": [], + "label": "telemetryCounter$", + "description": [ + "\nObservable to emit the stats of the processed events." + ], + "signature": [ + "Observable", + "<", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.TelemetryCounter", + "text": "TelemetryCounter" + }, + "> | undefined" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nSends all the enqueued events and fulfills the returned promise." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.IShipper.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nShutdown the shipper." + ], + "signature": [ + "() => void" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.OptInConfig", + "type": "Interface", + "tags": [], + "label": "OptInConfig", + "description": [ + "\nOptions for the optIn API" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.OptInConfig.global", + "type": "Object", + "tags": [], + "label": "global", + "description": [ + "\nControls the global enabled/disabled behaviour of the client and shippers." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.OptInConfigPerType", + "text": "OptInConfigPerType" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.OptInConfig.event_types", + "type": "Object", + "tags": [], + "label": "event_types", + "description": [ + "\nControls if an event type should be disabled for a specific type of shipper." + ], + "signature": [ + "Record | undefined" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.OptInConfigPerType", + "type": "Interface", + "tags": [], + "label": "OptInConfigPerType", + "description": [ + "\nSets whether a type of event is enabled/disabled globally or per shipper." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.OptInConfigPerType.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [ + "\nThe event type is globally enabled." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.OptInConfigPerType.shippers", + "type": "Object", + "tags": [], + "label": "shippers", + "description": [ + "\nControls if an event type should be disabled for a specific type of shipper." + ], + "signature": [ + "Record | undefined" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.RegisterShipperOpts", + "type": "Interface", + "tags": [], + "label": "RegisterShipperOpts", + "description": [ + "\nOptional options to register a shipper" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaArray", + "type": "Interface", + "tags": [], + "label": "SchemaArray", + "description": [ + "\nSchema to represent an array" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " extends ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMeta", + "text": "SchemaMeta" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaArray.type", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "The type must be an array" + ], + "signature": [ + "\"array\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaArray.items", + "type": "CompoundType", + "tags": [], + "label": "items", + "description": [ + "The schema of the items in the array is defined in the `items` property" + ], + "signature": [ + "{ type: \"pass_through\"; _meta: { description: string; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + "; } | (unknown extends Value ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends (infer U)[] | readonly (infer U)[] ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " : NonNullable extends Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends object ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + ")" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaChildValue", + "type": "Interface", + "tags": [], + "label": "SchemaChildValue", + "description": [ + "\nSchema to define a primitive value" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaChildValue.type", + "type": "Uncategorized", + "tags": [], + "label": "type", + "description": [ + "The type of the value" + ], + "signature": [ + "NonNullable extends string | Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaStringTypes", + "text": "AllowedSchemaStringTypes" + }, + " : NonNullable extends number ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaNumberTypes", + "text": "AllowedSchemaNumberTypes" + }, + " : NonNullable extends boolean ? \"boolean\" : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaTypes", + "text": "AllowedSchemaTypes" + } + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaChildValue._meta", + "type": "CompoundType", + "tags": [], + "label": "_meta", + "description": [ + "Meta properties of the value: description and is optional" + ], + "signature": [ + "{ description: string; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaMeta", + "type": "Interface", + "tags": [], + "label": "SchemaMeta", + "description": [ + "\nSchema meta with optional description" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMeta", + "text": "SchemaMeta" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaMeta._meta", + "type": "CompoundType", + "tags": [], + "label": "_meta", + "description": [ + "Meta properties of the pass through: description and is optional" + ], + "signature": [ + "({ description?: string | undefined; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + ") | undefined" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaObject", + "type": "Interface", + "tags": [], + "label": "SchemaObject", + "description": [ + "\nSchema to represent an object" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " extends ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMeta", + "text": "SchemaMeta" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaObject.properties", + "type": "Object", + "tags": [], + "label": "properties", + "description": [ + "\nThe schemas of the keys of the object are defined in the `properties` object." + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ShipperClassConstructor", + "type": "Interface", + "tags": [], + "label": "ShipperClassConstructor", + "description": [ + "\nConstructor of a {@link IShipper}" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ShipperClassConstructor", + "text": "ShipperClassConstructor" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ShipperClassConstructor.shipperName", + "type": "string", + "tags": [], + "label": "shipperName", + "description": [ + "\nThe shipper's unique name" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ShipperClassConstructor.new", + "type": "Function", + "tags": [], + "label": "new", + "description": [ + "\nThe constructor" + ], + "signature": [ + "any" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ShipperClassConstructor.new.$1", + "type": "Uncategorized", + "tags": [], + "label": "config", + "description": [ + "The shipper's custom config" + ], + "signature": [ + "Config" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ShipperClassConstructor.new.$2", + "type": "Object", + "tags": [], + "label": "initContext", + "description": [ + "Common context {@link AnalyticsClientInitContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AnalyticsClientInitContext", + "text": "AnalyticsClientInitContext" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.TelemetryCounter", + "type": "Interface", + "tags": [], + "label": "TelemetryCounter", + "description": [ + "\nShape of the events emitted by the telemetryCounter$ observable" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.TelemetryCounter.type", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [ + "\n{@link TelemetryCounterType}" + ], + "signature": [ + "\"succeeded\" | \"failed\" | \"enqueued\" | \"sent_to_shipper\" | \"dropped\"" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.TelemetryCounter.source", + "type": "string", + "tags": [], + "label": "source", + "description": [ + "\nWho emitted the event? It can be \"client\" or the name of the shipper." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.TelemetryCounter.event_type", + "type": "string", + "tags": [], + "label": "event_type", + "description": [ + "\nThe event type the success/failure/drop event refers to." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.TelemetryCounter.code", + "type": "string", + "tags": [], + "label": "code", + "description": [ + "\nCode to provide additional information about the success or failure. Examples are 200/400/504/ValidationError/UnknownError" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.TelemetryCounter.count", + "type": "number", + "tags": [], + "label": "count", + "description": [ + "\nThe number of events that this counter refers to." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.AllowedSchemaBooleanTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaBooleanTypes", + "description": [ + "Types matching boolean values" + ], + "signature": [ + "\"boolean\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.AllowedSchemaNumberTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaNumberTypes", + "description": [ + "Types matching number values" + ], + "signature": [ + "\"date\" | \"integer\" | \"long\" | \"short\" | \"byte\" | \"float\" | \"double\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.AllowedSchemaStringTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaStringTypes", + "description": [ + "Types matching string values" + ], + "signature": [ + "\"keyword\" | \"text\" | \"date\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.AllowedSchemaTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaTypes", + "description": [ + "\nPossible type values in the schema" + ], + "signature": [ + "\"boolean\" | \"keyword\" | \"text\" | \"date\" | \"integer\" | \"long\" | \"short\" | \"byte\" | \"float\" | \"double\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-analytics-server", "id": "def-common.AnalyticsServicePreboot", @@ -34,9 +2934,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -44,49 +2944,49 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, ">; registerEventType: (eventTypeOps: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.EventTypeOpts", "text": "EventTypeOpts" }, ") => void; registerShipper: (Shipper: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ShipperClassConstructor", "text": "ShipperClassConstructor" }, ", shipperConfig: ShipperConfig, opts?: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.RegisterShipperOpts", "text": "RegisterShipperOpts" }, " | undefined) => void; registerContextProvider: (contextProviderOpts: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ContextProviderOpts", "text": "ContextProviderOpts" }, @@ -109,9 +3009,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -119,49 +3019,49 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, ">; registerEventType: (eventTypeOps: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.EventTypeOpts", "text": "EventTypeOpts" }, ") => void; registerShipper: (Shipper: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ShipperClassConstructor", "text": "ShipperClassConstructor" }, ", shipperConfig: ShipperConfig, opts?: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.RegisterShipperOpts", "text": "RegisterShipperOpts" }, " | undefined) => void; registerContextProvider: (contextProviderOpts: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ContextProviderOpts", "text": "ContextProviderOpts" }, @@ -184,9 +3084,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -194,9 +3094,9 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, @@ -206,6 +3106,237 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ContextProviderName", + "type": "Type", + "tags": [], + "label": "ContextProviderName", + "description": [ + "\nContextProviderName used for indexed structures. Only used to improve the readability of the types" + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.EventType", + "type": "Type", + "tags": [], + "label": "EventType", + "description": [ + "\nEvent Type used for indexed structures. Only used to improve the readability of the types" + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.PossibleSchemaTypes", + "type": "Type", + "tags": [], + "label": "PossibleSchemaTypes", + "description": [ + "\nHelper to ensure the declared types match the schema types" + ], + "signature": [ + "Value extends string | Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaStringTypes", + "text": "AllowedSchemaStringTypes" + }, + " : Value extends number ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaNumberTypes", + "text": "AllowedSchemaNumberTypes" + }, + " : Value extends boolean ? \"boolean\" : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaTypes", + "text": "AllowedSchemaTypes" + } + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.RootSchema", + "type": "Type", + "tags": [], + "label": "RootSchema", + "description": [ + "\nSchema definition to match the structure of the properties provided.\n" + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaMetaOptional", + "type": "Type", + "tags": [], + "label": "SchemaMetaOptional", + "description": [ + "\nEnforces { optional: true } if the value can be undefined" + ], + "signature": [ + "unknown extends Value ? { optional?: boolean | undefined; } : undefined extends Value ? { optional: true; } : { optional?: false | undefined; }" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.SchemaValue", + "type": "Type", + "tags": [], + "label": "SchemaValue", + "description": [ + "\nType that defines all the possible values that the Schema accepts.\nThese types definitions are helping to identify earlier the possible missing `properties` nesting when\nmanually defining the schemas." + ], + "signature": [ + "{ type: \"pass_through\"; _meta: { description: string; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + "; } | (unknown extends Value ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends (infer U)[] | readonly (infer U)[] ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " : NonNullable extends Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends object ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + ")" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.ShipperName", + "type": "Type", + "tags": [], + "label": "ShipperName", + "description": [ + "\nShipper Name used for indexed structures. Only used to improve the readability of the types" + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-common.TelemetryCounterType", + "type": "Type", + "tags": [], + "label": "TelemetryCounterType", + "description": [ + "\nIndicates if the event contains data about succeeded, failed or dropped events:\n- enqueued: The event was accepted and will be sent to the shippers when they become available (and opt-in === true).\n- sent_to_shipper: The event was sent to at least one shipper.\n- succeeded: The event was successfully sent by the shipper.\n- failed: There was an error when processing/shipping the event. Refer to the Telemetry Counter's code for the reason.\n- dropped: The event was dropped from the queue. Refer to the Telemetry Counter's code for the reason." + ], + "signature": [ + "\"succeeded\" | \"failed\" | \"enqueued\" | \"sent_to_shipper\" | \"dropped\"" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index b1281d75c3b3de..e90a091217ad80 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; @@ -21,10 +21,13 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3 | 0 | 0 | 0 | +| 100 | 0 | 0 | 0 | ## Common +### Interfaces + + ### Consts, variables and types diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index 7de21c211151cb..0e60a56e9cfcee 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index 713977cd2472c2..1bbdd8746f8f8f 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser.mdx b/api_docs/kbn_core_application_browser.mdx index f251d7a1c93507..6b76538ad3b796 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser'] --- import kbnCoreApplicationBrowserObj from './kbn_core_application_browser.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_internal.mdx b/api_docs/kbn_core_application_browser_internal.mdx index f981d646c6fb37..d83bda2ad887de 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-internal'] --- import kbnCoreApplicationBrowserInternalObj from './kbn_core_application_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_mocks.mdx b/api_docs/kbn_core_application_browser_mocks.mdx index bef8995e9654bd..34097db0fd1ae6 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-mocks'] --- import kbnCoreApplicationBrowserMocksObj from './kbn_core_application_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_common.mdx b/api_docs/kbn_core_application_common.mdx index 16145d3c11fafc..459d3ad7f0a1df 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-common'] --- import kbnCoreApplicationCommonObj from './kbn_core_application_common.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_internal.devdocs.json b/api_docs/kbn_core_apps_browser_internal.devdocs.json index 4f9ba443d83110..d243920c1c1f9b 100644 --- a/api_docs/kbn_core_apps_browser_internal.devdocs.json +++ b/api_docs/kbn_core_apps_browser_internal.devdocs.json @@ -380,9 +380,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -390,9 +390,9 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, diff --git a/api_docs/kbn_core_apps_browser_internal.mdx b/api_docs/kbn_core_apps_browser_internal.mdx index 18fcb5acd1646d..deebf2082410e4 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-internal'] --- import kbnCoreAppsBrowserInternalObj from './kbn_core_apps_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_mocks.mdx b/api_docs/kbn_core_apps_browser_mocks.mdx index e08586791cb808..92c43aa8d20a8c 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index b295697eba559d..e3bfe07de819cb 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index eee3e8ec637f93..83361db92ba267 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index 94aacc78b60c15..2d4abb86584984 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 970a80356039fc..5730e672d8684a 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index a3ee47d6811bfa..0093286db5fb85 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_browser_mocks.mdx b/api_docs/kbn_core_capabilities_browser_mocks.mdx index 1b9697f69616d3..2c0c272df52135 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-browser-mocks'] --- import kbnCoreCapabilitiesBrowserMocksObj from './kbn_core_capabilities_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 30cceca53d2ebd..c9d891961606ce 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index cc6cb4c39c1c21..51221490afe8c5 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 12c6007f628482..2175735f414c93 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.devdocs.json b/api_docs/kbn_core_chrome_browser.devdocs.json index 3972f641350132..66c2b4398c08c2 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -3716,7 +3716,7 @@ "label": "AppDeepLinkId", "description": [], "signature": [ - "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"metrics\" | \"management\" | \"synthetics\" | \"ux\" | \"apm\" | \"logs\" | \"profiling\" | \"dashboards\" | \"observabilityAIAssistant\" | \"home\" | \"canvas\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:singleMetricViewer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:logRateAnalysis\" | \"ml:logPatternAnalysis\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:settings\" | \"management:dataViews\" | \"management:spaces\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:cross_cluster_replication\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchInferenceEndpoints\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"observability-logs-explorer\" | \"observabilityOnboarding\" | \"slo\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:services\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"profiling:functions\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\" | \"fleet:agents\"" + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"metrics\" | \"management\" | \"synthetics\" | \"ux\" | \"apm\" | \"logs\" | \"profiling\" | \"dashboards\" | \"observabilityAIAssistant\" | \"home\" | \"canvas\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:singleMetricViewer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:logRateAnalysis\" | \"ml:logPatternAnalysis\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:settings\" | \"management:dataViews\" | \"management:spaces\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:cross_cluster_replication\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchInferenceEndpoints\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"observability-logs-explorer\" | \"observabilityOnboarding\" | \"slo\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:services\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"profiling:functions\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:coverage-overview\" | \"securitySolutionUI:notes-management\" | \"fleet:settings\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\" | \"fleet:agents\"" ], "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index df65336afe5387..71105415fb4ca2 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index 5381f189870cb9..df950e030dec07 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser-mocks'] --- import kbnCoreChromeBrowserMocksObj from './kbn_core_chrome_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 6794b366689c15..9eec1a1692c158 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 4ff34e4adefc22..2e6eebc20e1ab1 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index e81870b643c879..c499b048c93440 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index 6617eb567d073a..df9652c4f6d7ec 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index d84a80e9e697b8..9ce3fd7b279063 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index 7b61b93bf6cc9f..23632cdbbd9ac2 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index 31cfa4d4e45f9f..d23c897cecffab 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index bf2dd1174975c6..6f258fcfc8b48b 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 2c5c656d5a1738..90daf5fa734f36 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index 0eef07d37f2f67..f657bd0dc847e2 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index c48a04beced54c..e5f76f49825dd6 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index 368228a7244506..9a20d9cb1f7fec 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server.mdx b/api_docs/kbn_core_deprecations_server.mdx index 189c9acfe34dc7..92b19b18195574 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server'] --- import kbnCoreDeprecationsServerObj from './kbn_core_deprecations_server.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_internal.mdx b/api_docs/kbn_core_deprecations_server_internal.mdx index 4f27d9d7bdc27a..d5df05b8651575 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-internal'] --- import kbnCoreDeprecationsServerInternalObj from './kbn_core_deprecations_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_mocks.mdx b/api_docs/kbn_core_deprecations_server_mocks.mdx index a6780bf1df2ea8..78e9a91330219e 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-mocks'] --- import kbnCoreDeprecationsServerMocksObj from './kbn_core_deprecations_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index 40fdbe57f7aec7..8336c45fbe0c2f 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index 90d2f8adc9c27a..cda2ac5294b204 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 347b7e5ca73722..612ce5f4084cb2 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 1d06db5d65017a..a65bfc25d7e6e5 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index dffaee0aef2270..674666ba6ebd24 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 078d393221f854..7904772ed2ae27 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 1b33d6e1e1d435..e7d4c7a2ac357b 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 78c2fb36d6e18e..5e73f0659d04b8 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 81c7b543e5a395..75bcf0def4b57a 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index e9c8b9fb706e45..5eb9304aac3171 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index 201c9d3d19e46f..8ba4a516a391b3 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index 3a7e7795ab0de9..2770e6e0bf0cb6 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 56201fe91ba97b..338cfc8f178abc 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index d8f2b10177c2ab..7bd144d8c9668c 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index 2b252e07e33858..2943e8c03296f6 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 66a96931f2fcc8..5778a1ec261833 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index dab20d8cc1900d..485e7e1e79c368 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index 0563ccd1b81654..1dc6be712cf05f 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index 12072174cb8f0b..8dd268062f9c7d 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index acef91e377e5ef..2b593020653fdd 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 6cd249cc3e4df7..cf2c050db360b7 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 4e94ae5e5a8f15..77688dedbcd7af 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index 6c1070c0eaf011..565afd6b084f11 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index 8fc34ad8c65e18..0558d5a0eed695 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index 44fc25a15d19e3..5f7488eb7179f2 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index abb6ef52263091..afd1291384dd20 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index dcca80ea28e061..a0f4412ee86e19 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index 509693ecd745a7..94f41e2228c568 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index 8a70bb7f215a61..aded1566dcffd7 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.devdocs.json b/api_docs/kbn_core_http_router_server_internal.devdocs.json index 91c3ad7da3110c..3debd264e86624 100644 --- a/api_docs/kbn_core_http_router_server_internal.devdocs.json +++ b/api_docs/kbn_core_http_router_server_internal.devdocs.json @@ -187,7 +187,7 @@ }, "<", "Method", - ">, \"description\" | \"access\"> | undefined; access: ", + ">, \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -195,7 +195,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.ts", "deprecated": false, @@ -266,7 +266,7 @@ }, "<", "Method", - ">, \"description\" | \"access\"> | undefined; access: ", + ">, \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -274,7 +274,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.ts", "deprecated": false, @@ -345,7 +345,7 @@ }, "<", "Method", - ">, \"description\" | \"access\"> | undefined; access: ", + ">, \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -353,7 +353,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.ts", "deprecated": false, @@ -424,7 +424,7 @@ }, "<", "Method", - ">, \"description\" | \"access\"> | undefined; access: ", + ">, \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -432,7 +432,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.ts", "deprecated": false, @@ -503,7 +503,7 @@ }, "<", "Method", - ">, \"description\" | \"access\"> | undefined; access: ", + ">, \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -511,7 +511,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.ts", "deprecated": false, diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index c7b81733f49913..dcdcbc84d6529f 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.devdocs.json b/api_docs/kbn_core_http_router_server_mocks.devdocs.json index ee55bc61e06d30..de2f1580a0cb24 100644 --- a/api_docs/kbn_core_http_router_server_mocks.devdocs.json +++ b/api_docs/kbn_core_http_router_server_mocks.devdocs.json @@ -80,7 +80,7 @@ "section": "def-common.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"description\" | \"access\"> | undefined; access: ", + ", \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -88,7 +88,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts", "deprecated": false, diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index ee3e10bf451476..f5d32c20ea0990 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index afadd6b9e71347..6efa1875aa8c9b 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -3510,6 +3510,10 @@ "plugin": "@kbn/core-apps-server-internal", "path": "packages/core/apps/core-apps-server-internal/src/core_app.ts" }, + { + "plugin": "usageCollection", + "path": "src/plugins/usage_collection/server/routes/stats/stats.ts" + }, { "plugin": "licensing", "path": "x-pack/plugins/licensing/server/routes/info.ts" @@ -3522,10 +3526,6 @@ "plugin": "features", "path": "x-pack/plugins/features/server/routes/index.ts" }, - { - "plugin": "usageCollection", - "path": "src/plugins/usage_collection/server/routes/stats/stats.ts" - }, { "plugin": "customIntegrations", "path": "src/plugins/custom_integrations/server/routes/define_routes.ts" @@ -6180,6 +6180,10 @@ "plugin": "@kbn/core-capabilities-server-internal", "path": "packages/core/capabilities/core-capabilities-server-internal/src/routes/resolve_capabilities.ts" }, + { + "plugin": "usageCollection", + "path": "src/plugins/usage_collection/server/routes/ui_counters.ts" + }, { "plugin": "licensing", "path": "x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts" @@ -6188,10 +6192,6 @@ "plugin": "licensing", "path": "x-pack/plugins/licensing/server/routes/internal/register_feature.ts" }, - { - "plugin": "usageCollection", - "path": "src/plugins/usage_collection/server/routes/ui_counters.ts" - }, { "plugin": "home", "path": "src/plugins/home/server/services/sample_data/routes/install.ts" @@ -12610,6 +12610,22 @@ "path": "packages/core/http/core-http-server/src/router/route.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-common.RouteConfigOptions.deprecated", + "type": "CompoundType", + "tags": [], + "label": "deprecated", + "description": [ + "\nSetting this to `true` declares this route to be deprecated. Consumers SHOULD\nrefrain from usage of this route.\n" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/core/http/core-http-server/src/router/route.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -14327,6 +14343,10 @@ "plugin": "elasticAssistant", "path": "x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.ts" }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts" + }, { "plugin": "logsShared", "path": "x-pack/plugins/observability_solution/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" @@ -14619,6 +14639,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/get.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/privileges.ts" @@ -14906,7 +14930,7 @@ "section": "def-common.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"description\" | \"access\"> | undefined; access: ", + ", \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -14914,7 +14938,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-server/src/versioning/types.ts", "deprecated": false, @@ -15197,7 +15221,7 @@ "section": "def-common.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"description\" | \"access\"> | undefined; access: ", + ", \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -15205,7 +15229,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-server/src/versioning/types.ts", "deprecated": false, @@ -15721,6 +15745,14 @@ "plugin": "elasticAssistant", "path": "x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/bulk_actions_route.ts" }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts" + }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts" + }, { "plugin": "logsShared", "path": "x-pack/plugins/observability_solution/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" @@ -16005,6 +16037,14 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts" @@ -16125,10 +16165,6 @@ "plugin": "synthetics", "path": "x-pack/plugins/observability_solution/synthetics/server/server.ts" }, - { - "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts" - }, { "plugin": "controls", "path": "src/plugins/controls/server/options_list/options_list_suggestions_route.ts" @@ -16236,7 +16272,7 @@ "section": "def-common.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"description\" | \"access\"> | undefined; access: ", + ", \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -16244,7 +16280,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-server/src/versioning/types.ts", "deprecated": false, @@ -16371,7 +16407,7 @@ "section": "def-common.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"description\" | \"access\"> | undefined; access: ", + ", \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -16379,7 +16415,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-server/src/versioning/types.ts", "deprecated": false, @@ -16583,6 +16619,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/delete.ts" + }, { "plugin": "synthetics", "path": "x-pack/plugins/observability_solution/synthetics/server/server.ts" @@ -16638,7 +16678,7 @@ "section": "def-common.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"description\" | \"access\"> | undefined; access: ", + ", \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -16646,7 +16686,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-server/src/versioning/types.ts", "deprecated": false, @@ -19341,7 +19381,7 @@ "section": "def-common.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"description\" | \"access\"> | undefined; access: ", + ", \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -19349,7 +19389,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-server/src/versioning/types.ts", "deprecated": false, @@ -19417,7 +19457,7 @@ "section": "def-common.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"description\" | \"access\"> | undefined; access: ", + ", \"description\" | \"deprecated\" | \"access\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "common", @@ -19425,7 +19465,7 @@ "section": "def-common.RouteAccess", "text": "RouteAccess" }, - "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; }" + "; enableQueryVersion?: boolean | undefined; summary?: string | undefined; description?: string | undefined; deprecated?: boolean | undefined; }" ], "path": "packages/core/http/core-http-server/src/versioning/types.ts", "deprecated": false, diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index c59369bdb598ac..3d4ca4db806151 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 488 | 2 | 193 | 0 | +| 489 | 2 | 193 | 0 | ## Common diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 94a84e11ee872b..403fc01ea0b4da 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index 398c4b490aeffb..2c11130958d721 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index cef2050e92def1..293fa964ee4a5a 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index a0e66b8eab87cd..b65b47da9991ec 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index 5fc017df1af979..1078b9422550d3 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index 7942a398e549b0..6e63af728c0862 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index 95e656990580d8..399f8f707f150e 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 00307bd30d48f3..e09f4d57977fd8 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 9a3d9633892ee6..53e799d45f3307 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index 30f7e9f75dbfc4..742fb3ae3e247d 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.devdocs.json b/api_docs/kbn_core_lifecycle_browser.devdocs.json index 249fb73e18a740..ad2d7ba96eb1fc 100644 --- a/api_docs/kbn_core_lifecycle_browser.devdocs.json +++ b/api_docs/kbn_core_lifecycle_browser.devdocs.json @@ -55,9 +55,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -65,49 +65,49 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, ">; registerEventType: (eventTypeOps: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.EventTypeOpts", "text": "EventTypeOpts" }, ") => void; registerShipper: (Shipper: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ShipperClassConstructor", "text": "ShipperClassConstructor" }, ", shipperConfig: ShipperConfig, opts?: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.RegisterShipperOpts", "text": "RegisterShipperOpts" }, " | undefined) => void; registerContextProvider: (contextProviderOpts: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ContextProviderOpts", "text": "ContextProviderOpts" }, @@ -437,9 +437,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -447,9 +447,9 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index b0c301e1425d0e..bfeb9a0c6fa54b 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index ddec0ce7847f4e..3e3d6f91030618 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.devdocs.json b/api_docs/kbn_core_lifecycle_server.devdocs.json index 39e4ac4c5f0317..b52260d08327ce 100644 --- a/api_docs/kbn_core_lifecycle_server.devdocs.json +++ b/api_docs/kbn_core_lifecycle_server.devdocs.json @@ -45,9 +45,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -55,49 +55,49 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, ">; registerEventType: (eventTypeOps: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.EventTypeOpts", "text": "EventTypeOpts" }, ") => void; registerShipper: (Shipper: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ShipperClassConstructor", "text": "ShipperClassConstructor" }, ", shipperConfig: ShipperConfig, opts?: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.RegisterShipperOpts", "text": "RegisterShipperOpts" }, " | undefined) => void; registerContextProvider: (contextProviderOpts: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ContextProviderOpts", "text": "ContextProviderOpts" }, @@ -220,9 +220,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -230,49 +230,49 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, ">; registerEventType: (eventTypeOps: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.EventTypeOpts", "text": "EventTypeOpts" }, ") => void; registerShipper: (Shipper: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ShipperClassConstructor", "text": "ShipperClassConstructor" }, ", shipperConfig: ShipperConfig, opts?: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.RegisterShipperOpts", "text": "RegisterShipperOpts" }, " | undefined) => void; registerContextProvider: (contextProviderOpts: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ContextProviderOpts", "text": "ContextProviderOpts" }, @@ -727,9 +727,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -737,9 +737,9 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index 7ec9130a81c25e..540a363e5f08a0 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index 9d93dec58ef0bc..bcd4440d8c4278 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index d75280e591054e..ebe1d709f36263 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index 1528d1873342dd..81ced9b396fd30 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index a9e1c8beb172aa..462ee206a17eab 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 09c173f792ef9d..547d8e1f274c3f 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 272ce8ea971a34..46007186a4cf7d 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 767835c5efb7d8..18e66be6b7a3c4 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 7f468539935324..464491aa5691de 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index 741ada65111196..e01424863afb0e 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 20cc76f5b09ef2..ab8dd8c9df9046 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index e99b6d6168e727..3ec6efa1098003 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 0214af178c9f07..61f1267a833b89 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 65540f34578971..83f6a6541d4256 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index 61f89ff5f2cb32..380f12a5efa547 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index ec3d7f9b861295..7f2fd98b2ad188 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index 79310036bbe9a6..260678120bf7b9 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index a3998cca34a3a8..19a018e82aa930 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index 45310c0840b606..a37cddaa83ce95 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index c85edd3257f91b..4e07e307cd3ef7 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index 3393b2a4021216..ce21d35d70b636 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 5d69b7ee580e02..3ffde560b9cb8d 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index f0cae503b4f1c6..394a55506fc30f 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index 99d1abe125a68e..0f2265927f8e94 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index 6c97ce67d86a45..2f74db77bc2066 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index 88aba70f779258..36ded0cd67d6c0 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 247f7c81352146..568715e2a0baa1 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 0810e0ba2d7594..f0ffacb8de493d 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index a1ad60f25d392f..ae491b22583cf3 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index f20648b50a0b16..42345a01632551 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index 5de01f17af3716..8880edcde44d23 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index 5fb49017a91587..f50b1493d6bc0b 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index 4291832fd0738f..c602f636b9874d 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index a6dcf012a32531..7cb65d62fa0d12 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index fba55c27a9059d..9f91e8923304d7 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 1f4246ce25225d..874e3e0bdd0ea1 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index c313d47ec8a2f7..ecffad213e4ff3 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index df005b36ab1619..e0cc5522906d03 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index 6a03625c7cbeca..0c5b314f1f6603 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index ebe9f47d41e467..752ecbf87d7e60 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 2eddae6645152b..c433502eed4304 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 820ca0283b29e3..35a7a834c69bcf 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index b4ba29e7cd7ac0..68d6a677696116 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index 318f9346661351..4a1337ba6374f2 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index 61bd3b20ba2126..8e6a4bbac0003f 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index 007e6d0007869a..80a214f8e8bccf 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index b287508e816f6a..e4c15b37732ab2 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index e60781764e9dd0..78665054e2d512 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 0ebdb8b26557d7..98fc56e33289f0 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index 4b2a55c6e396c1..19151bb3375275 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index 43cfbead9833d1..ff2d640d3dff19 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser.mdx b/api_docs/kbn_core_security_browser.mdx index 5be1e78d5da9d6..0918bd4435b486 100644 --- a/api_docs/kbn_core_security_browser.mdx +++ b/api_docs/kbn_core_security_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser title: "@kbn/core-security-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser'] --- import kbnCoreSecurityBrowserObj from './kbn_core_security_browser.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_internal.mdx b/api_docs/kbn_core_security_browser_internal.mdx index 991a583cc5e127..bb1ed61f821731 100644 --- a/api_docs/kbn_core_security_browser_internal.mdx +++ b/api_docs/kbn_core_security_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-internal title: "@kbn/core-security-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-internal'] --- import kbnCoreSecurityBrowserInternalObj from './kbn_core_security_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_mocks.mdx b/api_docs/kbn_core_security_browser_mocks.mdx index c3c1737fdc9ab5..300d673be9d5c2 100644 --- a/api_docs/kbn_core_security_browser_mocks.mdx +++ b/api_docs/kbn_core_security_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-mocks title: "@kbn/core-security-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-mocks'] --- import kbnCoreSecurityBrowserMocksObj from './kbn_core_security_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_security_common.mdx b/api_docs/kbn_core_security_common.mdx index 9670c5a59d448b..5078e7aac70039 100644 --- a/api_docs/kbn_core_security_common.mdx +++ b/api_docs/kbn_core_security_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-common title: "@kbn/core-security-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-common'] --- import kbnCoreSecurityCommonObj from './kbn_core_security_common.devdocs.json'; diff --git a/api_docs/kbn_core_security_server.mdx b/api_docs/kbn_core_security_server.mdx index 35be18d36b1581..84c9098187bbbc 100644 --- a/api_docs/kbn_core_security_server.mdx +++ b/api_docs/kbn_core_security_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server title: "@kbn/core-security-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server'] --- import kbnCoreSecurityServerObj from './kbn_core_security_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_internal.mdx b/api_docs/kbn_core_security_server_internal.mdx index 3b0ec3fe786994..2bd601031c0c35 100644 --- a/api_docs/kbn_core_security_server_internal.mdx +++ b/api_docs/kbn_core_security_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-internal title: "@kbn/core-security-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-internal'] --- import kbnCoreSecurityServerInternalObj from './kbn_core_security_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_mocks.mdx b/api_docs/kbn_core_security_server_mocks.mdx index ac515de31e89e0..7c7d458c61b643 100644 --- a/api_docs/kbn_core_security_server_mocks.mdx +++ b/api_docs/kbn_core_security_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-mocks title: "@kbn/core-security-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-mocks'] --- import kbnCoreSecurityServerMocksObj from './kbn_core_security_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index dc33a315941e4c..b2be2d573a3833 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index b843121cbd69aa..a4e723953e857d 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index ed4b208f4a796a..226d66fd93b4cc 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.devdocs.json b/api_docs/kbn_core_status_server_internal.devdocs.json index 107828999c77f2..5a27f026247ba3 100644 --- a/api_docs/kbn_core_status_server_internal.devdocs.json +++ b/api_docs/kbn_core_status_server_internal.devdocs.json @@ -296,9 +296,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -306,49 +306,49 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, ">; registerEventType: (eventTypeOps: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.EventTypeOpts", "text": "EventTypeOpts" }, ") => void; registerShipper: (Shipper: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ShipperClassConstructor", "text": "ShipperClassConstructor" }, ", shipperConfig: ShipperConfig, opts?: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.RegisterShipperOpts", "text": "RegisterShipperOpts" }, " | undefined) => void; registerContextProvider: (contextProviderOpts: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.ContextProviderOpts", "text": "ContextProviderOpts" }, diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index 71ea68f7d5ba9d..fc208bda2f92bf 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index cc69f9a7c81753..da52f2f53ee6da 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index 0b27924382ad52..57d54bc469e26b 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index f937cd2d8a0a83..7dbb268d367bc7 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index ac242965cda10a..1bceadbf6500ec 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index 7a5d6babab383e..80dfcec841e4fe 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index bc9bd5e6045196..b5397439e4a133 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index e21547444a2005..08ee975d23ec62 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 1c73e73b8e24da..3a8b9886f7f8a2 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 9762a0bf00d2f2..888ce7638b70bc 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 6fc4bbaceccfa2..d2fe1dfd87a1b1 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 098a43228e2119..a80cfcb497d842 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index a678369d6eb6c0..2f7cad133b4cdf 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index 50f6a33ada34ed..fd3819d87139b7 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index ae5457505b3775..776cd00c33ba9d 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index dda6040547258d..66a0252c0743cf 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index 50bc0277179521..44ffdbee19eede 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index 9f5d7558f0cdee..8c86d7d90a81d7 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index 44e691739a9a42..167711a91f528e 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index b5853c26912dd7..91b5b01cc15bf4 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser.mdx b/api_docs/kbn_core_user_profile_browser.mdx index 3f847bb3cbb7ba..eb95315c988d1f 100644 --- a/api_docs/kbn_core_user_profile_browser.mdx +++ b/api_docs/kbn_core_user_profile_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser title: "@kbn/core-user-profile-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser'] --- import kbnCoreUserProfileBrowserObj from './kbn_core_user_profile_browser.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_internal.mdx b/api_docs/kbn_core_user_profile_browser_internal.mdx index bbcb96fe8d840b..c843246a61a828 100644 --- a/api_docs/kbn_core_user_profile_browser_internal.mdx +++ b/api_docs/kbn_core_user_profile_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-internal title: "@kbn/core-user-profile-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-internal'] --- import kbnCoreUserProfileBrowserInternalObj from './kbn_core_user_profile_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_mocks.mdx b/api_docs/kbn_core_user_profile_browser_mocks.mdx index c95de8602f92e1..befa003474b26b 100644 --- a/api_docs/kbn_core_user_profile_browser_mocks.mdx +++ b/api_docs/kbn_core_user_profile_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-mocks title: "@kbn/core-user-profile-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-mocks'] --- import kbnCoreUserProfileBrowserMocksObj from './kbn_core_user_profile_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_common.mdx b/api_docs/kbn_core_user_profile_common.mdx index e76fb89ad8be0e..f66ad47be61223 100644 --- a/api_docs/kbn_core_user_profile_common.mdx +++ b/api_docs/kbn_core_user_profile_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-common title: "@kbn/core-user-profile-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-common'] --- import kbnCoreUserProfileCommonObj from './kbn_core_user_profile_common.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server.mdx b/api_docs/kbn_core_user_profile_server.mdx index ef92831535c47d..0e15c25f306cbb 100644 --- a/api_docs/kbn_core_user_profile_server.mdx +++ b/api_docs/kbn_core_user_profile_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server title: "@kbn/core-user-profile-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server'] --- import kbnCoreUserProfileServerObj from './kbn_core_user_profile_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_internal.mdx b/api_docs/kbn_core_user_profile_server_internal.mdx index 422f1ce5a92bbe..41d57e14eb86d6 100644 --- a/api_docs/kbn_core_user_profile_server_internal.mdx +++ b/api_docs/kbn_core_user_profile_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-internal title: "@kbn/core-user-profile-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-internal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-internal'] --- import kbnCoreUserProfileServerInternalObj from './kbn_core_user_profile_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_mocks.mdx b/api_docs/kbn_core_user_profile_server_mocks.mdx index 6e82292c8f67a0..b86eb701b873fa 100644 --- a/api_docs/kbn_core_user_profile_server_mocks.mdx +++ b/api_docs/kbn_core_user_profile_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-mocks title: "@kbn/core-user-profile-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-mocks'] --- import kbnCoreUserProfileServerMocksObj from './kbn_core_user_profile_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index bb2abf7052d1a4..795d69dbb69e3f 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index e0530e82a349cd..a3aa62ecb73426 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index 8d6830288901c4..0738623f9c4cd2 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index 34122d21f55587..a222beae12053f 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_icons.mdx b/api_docs/kbn_custom_icons.mdx index 5c9edfafda6dd5..6bb317fa407d47 100644 --- a/api_docs/kbn_custom_icons.mdx +++ b/api_docs/kbn_custom_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-icons title: "@kbn/custom-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-icons plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-icons'] --- import kbnCustomIconsObj from './kbn_custom_icons.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index 2a1a10905c5e92..368d1d7209818d 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index 24d57726f53c4d..e3da1a3651de5a 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_forge.mdx b/api_docs/kbn_data_forge.mdx index 6c552996443a5b..aef3c64f677579 100644 --- a/api_docs/kbn_data_forge.mdx +++ b/api_docs/kbn_data_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-forge title: "@kbn/data-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-forge plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-forge'] --- import kbnDataForgeObj from './kbn_data_forge.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 56d6b807dcf962..932436e20308e7 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_data_stream_adapter.mdx b/api_docs/kbn_data_stream_adapter.mdx index d7755afb4bd0cf..50998407ddbfea 100644 --- a/api_docs/kbn_data_stream_adapter.mdx +++ b/api_docs/kbn_data_stream_adapter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-stream-adapter title: "@kbn/data-stream-adapter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-stream-adapter plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-stream-adapter'] --- import kbnDataStreamAdapterObj from './kbn_data_stream_adapter.devdocs.json'; diff --git a/api_docs/kbn_data_view_utils.devdocs.json b/api_docs/kbn_data_view_utils.devdocs.json index 0bacfe7a0aa461..bbef9faf79cd53 100644 --- a/api_docs/kbn_data_view_utils.devdocs.json +++ b/api_docs/kbn_data_view_utils.devdocs.json @@ -18,7 +18,74 @@ }, "common": { "classes": [], - "functions": [], + "functions": [ + { + "parentPluginId": "@kbn/data-view-utils", + "id": "def-common.createRegExpPatternFrom", + "type": "Function", + "tags": [], + "label": "createRegExpPatternFrom", + "description": [], + "signature": [ + "(basePatterns: string | string[]) => RegExp" + ], + "path": "packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/data-view-utils", + "id": "def-common.createRegExpPatternFrom.$1", + "type": "CompoundType", + "tags": [], + "label": "basePatterns", + "description": [], + "signature": [ + "string | string[]" + ], + "path": "packages/kbn-data-view-utils/src/utils/create_regexp_pattern_from.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/data-view-utils", + "id": "def-common.testPatternAgainstAllowedList", + "type": "Function", + "tags": [], + "label": "testPatternAgainstAllowedList", + "description": [], + "signature": [ + "(allowedList: (string | RegExp)[]) => (value: string) => boolean" + ], + "path": "packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/data-view-utils", + "id": "def-common.testPatternAgainstAllowedList.$1", + "type": "Array", + "tags": [], + "label": "allowedList", + "description": [], + "signature": [ + "(string | RegExp)[]" + ], + "path": "packages/kbn-data-view-utils/src/utils/test_pattern_against_allowed_list.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], "interfaces": [], "enums": [], "misc": [ diff --git a/api_docs/kbn_data_view_utils.mdx b/api_docs/kbn_data_view_utils.mdx index 3f9cfd3e15bacd..e03b8bc0f96175 100644 --- a/api_docs/kbn_data_view_utils.mdx +++ b/api_docs/kbn_data_view_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-view-utils title: "@kbn/data-view-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-view-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-view-utils'] --- import kbnDataViewUtilsObj from './kbn_data_view_utils.devdocs.json'; @@ -21,10 +21,13 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1 | 0 | 0 | 0 | +| 5 | 0 | 4 | 0 | ## Common +### Functions + + ### Consts, variables and types diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 9bb9de5ed5471f..e90b3a3e049810 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index 6f5b8882c4f5ae..3db3b8868e8a17 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index f4757ad7d18763..08891eda96b5fd 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_fleet.mdx b/api_docs/kbn_deeplinks_fleet.mdx index 96f0c8c0341cb3..2b6f29f578e49e 100644 --- a/api_docs/kbn_deeplinks_fleet.mdx +++ b/api_docs/kbn_deeplinks_fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-fleet title: "@kbn/deeplinks-fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-fleet plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-fleet'] --- import kbnDeeplinksFleetObj from './kbn_deeplinks_fleet.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index 8b229f4cc19f8b..31971c1739ba73 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index cc069e178f4bc1..7a2fe8066cfa91 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index d824e8064b963e..672f113f92ac84 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index 555bbbf62fdc21..43a1345190c313 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_security.devdocs.json b/api_docs/kbn_deeplinks_security.devdocs.json index 1e9a52bf2b3689..5eec00a0d93404 100644 --- a/api_docs/kbn_deeplinks_security.devdocs.json +++ b/api_docs/kbn_deeplinks_security.devdocs.json @@ -58,7 +58,7 @@ "label": "DeepLinkId", "description": [], "signature": [ - "\"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:coverage-overview\"" + "\"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:coverage-overview\" | \"securitySolutionUI:notes-management\"" ], "path": "packages/deeplinks/security/index.ts", "deprecated": false, @@ -73,7 +73,7 @@ "label": "LinkId", "description": [], "signature": [ - "\"\" | \"cases\" | \"alerts\" | \"rules\" | \"policy\" | \"overview\" | \"dashboards\" | \"cases_create\" | \"cases_configure\" | \"hosts\" | \"users\" | \"cloud_defend-policies\" | \"cloud_security_posture-dashboard\" | \"cloud_security_posture-findings\" | \"cloud_security_posture-benchmarks\" | \"kubernetes\" | \"network\" | \"data_quality\" | \"explore\" | \"assets\" | \"cloud_defend\" | \"administration\" | \"attack_discovery\" | \"blocklist\" | \"cloud_security_posture-rules\" | \"detections\" | \"detection_response\" | \"endpoints\" | \"event_filters\" | \"exceptions\" | \"host_isolation_exceptions\" | \"hosts-all\" | \"hosts-anomalies\" | \"hosts-risk\" | \"hosts-events\" | \"hosts-sessions\" | \"hosts-uncommon_processes\" | \"investigations\" | \"get_started\" | \"machine_learning-landing\" | \"network-anomalies\" | \"network-dns\" | \"network-events\" | \"network-flows\" | \"network-http\" | \"network-tls\" | \"response_actions_history\" | \"rules-add\" | \"rules-create\" | \"rules-landing\" | \"threat_intelligence\" | \"timelines\" | \"timelines-templates\" | \"trusted_apps\" | \"users-all\" | \"users-anomalies\" | \"users-authentications\" | \"users-events\" | \"users-risk\" | \"entity_analytics\" | \"entity_analytics-management\" | \"entity_analytics-asset-classification\" | \"coverage-overview\"" + "\"\" | \"cases\" | \"alerts\" | \"rules\" | \"policy\" | \"overview\" | \"dashboards\" | \"cases_create\" | \"cases_configure\" | \"hosts\" | \"users\" | \"cloud_defend-policies\" | \"cloud_security_posture-dashboard\" | \"cloud_security_posture-findings\" | \"cloud_security_posture-benchmarks\" | \"kubernetes\" | \"network\" | \"data_quality\" | \"explore\" | \"assets\" | \"cloud_defend\" | \"administration\" | \"attack_discovery\" | \"blocklist\" | \"cloud_security_posture-rules\" | \"detections\" | \"detection_response\" | \"endpoints\" | \"event_filters\" | \"exceptions\" | \"host_isolation_exceptions\" | \"hosts-all\" | \"hosts-anomalies\" | \"hosts-risk\" | \"hosts-events\" | \"hosts-sessions\" | \"hosts-uncommon_processes\" | \"investigations\" | \"get_started\" | \"machine_learning-landing\" | \"network-anomalies\" | \"network-dns\" | \"network-events\" | \"network-flows\" | \"network-http\" | \"network-tls\" | \"response_actions_history\" | \"rules-add\" | \"rules-create\" | \"rules-landing\" | \"threat_intelligence\" | \"timelines\" | \"timelines-templates\" | \"trusted_apps\" | \"users-all\" | \"users-anomalies\" | \"users-authentications\" | \"users-events\" | \"users-risk\" | \"entity_analytics\" | \"entity_analytics-management\" | \"entity_analytics-asset-classification\" | \"coverage-overview\" | \"notes-management\"" ], "path": "packages/deeplinks/security/index.ts", "deprecated": false, diff --git a/api_docs/kbn_deeplinks_security.mdx b/api_docs/kbn_deeplinks_security.mdx index 3a0f870d4b3354..1eb07631bd8aef 100644 --- a/api_docs/kbn_deeplinks_security.mdx +++ b/api_docs/kbn_deeplinks_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-security title: "@kbn/deeplinks-security" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-security plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-security'] --- import kbnDeeplinksSecurityObj from './kbn_deeplinks_security.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_shared.mdx b/api_docs/kbn_deeplinks_shared.mdx index f6f6ad56ad9461..c79f2f054e5e6b 100644 --- a/api_docs/kbn_deeplinks_shared.mdx +++ b/api_docs/kbn_deeplinks_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-shared title: "@kbn/deeplinks-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-shared plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-shared'] --- import kbnDeeplinksSharedObj from './kbn_deeplinks_shared.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index e14dddf6997f91..4cc118f0038c38 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index 243fd8639335c5..4e4c7a5e1cbbe5 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index 8c800bbe4517e8..752e3fdbd17ed9 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index face43c46780e4..0619209c5133dd 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 1217a0ca13fa9b..6dcc7055b3f005 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 9d914ba9978e52..5382194ebec168 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index c59ecdf80707bf..99148ba4dc8fd8 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 4a501d42c4ebd1..f5414936849fc5 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.devdocs.json b/api_docs/kbn_discover_utils.devdocs.json index 641ea8ff21b2e0..6777a3f093a666 100644 --- a/api_docs/kbn_discover_utils.devdocs.json +++ b/api_docs/kbn_discover_utils.devdocs.json @@ -279,6 +279,41 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.createLogsContextService", + "type": "Function", + "tags": [], + "label": "createLogsContextService", + "description": [], + "signature": [ + "(_deps?: ", + "LogsContextServiceDeps", + ") => { isLogsIndexPattern: (indexPattern: unknown) => boolean; }" + ], + "path": "packages/kbn-discover-utils/src/data_types/logs/logs_context_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.createLogsContextService.$1", + "type": "Object", + "tags": [], + "label": "_deps", + "description": [], + "signature": [ + "LogsContextServiceDeps" + ], + "path": "packages/kbn-discover-utils/src/data_types/logs/logs_context_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/discover-utils", "id": "def-common.formatFieldValue", @@ -1801,6 +1836,52 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.LogsContextService", + "type": "Interface", + "tags": [], + "label": "LogsContextService", + "description": [], + "path": "packages/kbn-discover-utils/src/data_types/logs/logs_context_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.LogsContextService.isLogsIndexPattern", + "type": "Function", + "tags": [], + "label": "isLogsIndexPattern", + "description": [], + "signature": [ + "(indexPattern: unknown) => boolean" + ], + "path": "packages/kbn-discover-utils/src/data_types/logs/logs_context_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.LogsContextService.isLogsIndexPattern.$1", + "type": "Unknown", + "tags": [], + "label": "indexPattern", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/kbn-discover-utils/src/data_types/logs/logs_context_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/discover-utils", "id": "def-common.LogStackTraceFields", @@ -1918,6 +1999,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.DEFAULT_ALLOWED_LOGS_BASE_PATTERNS", + "type": "Array", + "tags": [], + "label": "DEFAULT_ALLOWED_LOGS_BASE_PATTERNS", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-discover-utils/src/data_types/logs/logs_context_service.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/discover-utils", "id": "def-common.DEFAULT_COLUMNS_SETTING", diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index ff6d52f0aec76d..100bd04b1e3aa3 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 114 | 0 | 88 | 0 | +| 120 | 0 | 94 | 1 | ## Common diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 99b4070129b905..949b00b86eed29 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 1c009ad6ae1fba..b709c1656cde50 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index ad520c4d0940df..20f8a3b4caecd1 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt.devdocs.json b/api_docs/kbn_ebt.devdocs.json new file mode 100644 index 00000000000000..82e6770af4faca --- /dev/null +++ b/api_docs/kbn_ebt.devdocs.json @@ -0,0 +1,4130 @@ +{ + "id": "@kbn/ebt", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper", + "type": "Class", + "tags": [], + "label": "ElasticV3BrowserShipper", + "description": [ + "\nElastic V3 shipper to use in the browser." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ElasticV3BrowserShipper", + "text": "ElasticV3BrowserShipper" + }, + " implements ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.IShipper", + "text": "IShipper" + } + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.shipperName", + "type": "string", + "tags": [], + "label": "shipperName", + "description": [ + "Shipper's unique name" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.telemetryCounter$", + "type": "Object", + "tags": [], + "label": "telemetryCounter$", + "description": [ + "Observable to emit the stats of the processed events." + ], + "signature": [ + "Subject", + "<", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.TelemetryCounter", + "text": "TelemetryCounter" + }, + ">" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [ + "\nCreates a new instance of the {@link ElasticV3BrowserShipper}." + ], + "signature": [ + "any" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [ + "{@link ElasticV3ShipperOptions }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ElasticV3ShipperOptions", + "text": "ElasticV3ShipperOptions" + } + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.Unnamed.$2", + "type": "Object", + "tags": [], + "label": "initContext", + "description": [ + "{@link AnalyticsClientInitContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AnalyticsClientInitContext", + "text": "AnalyticsClientInitContext" + } + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.extendContext", + "type": "Function", + "tags": [], + "label": "extendContext", + "description": [ + "\nUses the `cluster_uuid` and `license_id` from the context to hold them in memory for the generation of the headers\nused later on in the HTTP request." + ], + "signature": [ + "(newContext: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + }, + ") => void" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.extendContext.$1", + "type": "Object", + "tags": [], + "label": "newContext", + "description": [ + "The full new context to set {@link EventContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + } + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nWhen `false`, it flushes the internal queue and stops sending events." + ], + "signature": [ + "(isOptedIn: boolean) => void" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.optIn.$1", + "type": "boolean", + "tags": [], + "label": "isOptedIn", + "description": [ + "`true` for resume sending events. `false` to stop." + ], + "signature": [ + "boolean" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.reportEvents", + "type": "Function", + "tags": [], + "label": "reportEvents", + "description": [ + "\nEnqueues the events to be sent to in a batched approach." + ], + "signature": [ + "(events: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]) => void" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.reportEvents.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [ + "batched events {@link Event }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nTriggers a flush of the internal queue to attempt to send any events held in the queue\nand resolves the returned promise once the queue is emptied." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3BrowserShipper.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nShuts down the shipper.\nTriggers a flush of the internal queue to attempt to send any events held in the queue." + ], + "signature": [ + "() => void" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/browser/src/browser_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper", + "type": "Class", + "tags": [], + "label": "ElasticV3ServerShipper", + "description": [ + "\nElastic V3 shipper to use on the server side." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ElasticV3ServerShipper", + "text": "ElasticV3ServerShipper" + }, + " implements ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.IShipper", + "text": "IShipper" + } + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.shipperName", + "type": "string", + "tags": [], + "label": "shipperName", + "description": [ + "Shipper's unique name" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.telemetryCounter$", + "type": "Object", + "tags": [], + "label": "telemetryCounter$", + "description": [ + "Observable to emit the stats of the processed events." + ], + "signature": [ + "Subject", + "<", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.TelemetryCounter", + "text": "TelemetryCounter" + }, + ">" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [ + "\nCreates a new instance of the {@link ElasticV3ServerShipper}." + ], + "signature": [ + "any" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [ + "{@link ElasticV3ShipperOptions }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ElasticV3ShipperOptions", + "text": "ElasticV3ShipperOptions" + } + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.Unnamed.$2", + "type": "Object", + "tags": [], + "label": "initContext", + "description": [ + "{@link AnalyticsClientInitContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AnalyticsClientInitContext", + "text": "AnalyticsClientInitContext" + } + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.extendContext", + "type": "Function", + "tags": [], + "label": "extendContext", + "description": [ + "\nUses the `cluster_uuid` and `license_id` from the context to hold them in memory for the generation of the headers\nused later on in the HTTP request." + ], + "signature": [ + "(newContext: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + }, + ") => void" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.extendContext.$1", + "type": "Object", + "tags": [], + "label": "newContext", + "description": [ + "The full new context to set {@link EventContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + } + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nWhen `false`, it flushes the internal queue and stops sending events." + ], + "signature": [ + "(isOptedIn: boolean) => void" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.optIn.$1", + "type": "boolean", + "tags": [], + "label": "isOptedIn", + "description": [ + "`true` for resume sending events. `false` to stop." + ], + "signature": [ + "boolean" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.reportEvents", + "type": "Function", + "tags": [], + "label": "reportEvents", + "description": [ + "\nEnqueues the events to be sent via the leaky bucket algorithm." + ], + "signature": [ + "(events: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]) => void" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.reportEvents.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [ + "batched events {@link Event }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nTriggers a flush of the internal queue to attempt to send any events held in the queue\nand resolves the returned promise once the queue is emptied." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ServerShipper.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nShuts down the shipper.\nTriggers a flush of the internal queue to attempt to send any events held in the queue." + ], + "signature": [ + "() => void" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/server/src/server_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper", + "type": "Class", + "tags": [], + "label": "FullStoryShipper", + "description": [ + "\nFullStory shipper." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.FullStoryShipper", + "text": "FullStoryShipper" + }, + " implements ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.IShipper", + "text": "IShipper" + } + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.shipperName", + "type": "string", + "tags": [], + "label": "shipperName", + "description": [ + "Shipper's unique name" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [ + "\nCreates a new instance of the FullStoryShipper." + ], + "signature": [ + "any" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "config", + "description": [ + "{@link FullStoryShipperConfig }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.FullStoryShipperConfig", + "text": "FullStoryShipperConfig" + } + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.Unnamed.$2", + "type": "Object", + "tags": [], + "label": "initContext", + "description": [ + "{@link AnalyticsClientInitContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AnalyticsClientInitContext", + "text": "AnalyticsClientInitContext" + } + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.extendContext", + "type": "Function", + "tags": [], + "label": "extendContext", + "description": [ + "\nCalls `fs.identify`, `fs.setUserVars` and `fs.setVars` depending on the fields provided in the newContext." + ], + "signature": [ + "(newContext: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + }, + ") => void" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.extendContext.$1", + "type": "Object", + "tags": [], + "label": "newContext", + "description": [ + "The full new context to set {@link EventContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + } + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nStops/restarts the shipping mechanism based on the value of isOptedIn" + ], + "signature": [ + "(isOptedIn: boolean) => void" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.optIn.$1", + "type": "boolean", + "tags": [], + "label": "isOptedIn", + "description": [ + "`true` for resume sending events. `false` to stop." + ], + "signature": [ + "boolean" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.reportEvents", + "type": "Function", + "tags": [], + "label": "reportEvents", + "description": [ + "\nFilters the events by the eventTypesAllowlist from the config.\nThen it transforms the event into a FS valid format and calls `fs.event`." + ], + "signature": [ + "(events: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]) => void" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.reportEvents.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [ + "batched events {@link Event }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nFlushes all internal queues of the shipper.\nIt doesn't really do anything inside because this shipper doesn't hold any internal queues." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipper.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nShuts down the shipper." + ], + "signature": [ + "() => void" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.AnalyticsClientInitContext", + "type": "Interface", + "tags": [], + "label": "AnalyticsClientInitContext", + "description": [ + "\nGeneral settings of the analytics client" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.AnalyticsClientInitContext.isDev", + "type": "boolean", + "tags": [], + "label": "isDev", + "description": [ + "\nBoolean indicating if it's running in developer mode." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.AnalyticsClientInitContext.sendTo", + "type": "CompoundType", + "tags": [], + "label": "sendTo", + "description": [ + "\nSpecify if the shippers should send their data to the production or staging environments." + ], + "signature": [ + "\"production\" | \"staging\"" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.AnalyticsClientInitContext.logger", + "type": "Object", + "tags": [], + "label": "logger", + "description": [ + "\nApplication-provided logger." + ], + "signature": [ + { + "pluginId": "@kbn/logging", + "scope": "common", + "docId": "kibKbnLoggingPluginApi", + "section": "def-common.Logger", + "text": "Logger" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ContextProviderOpts", + "type": "Interface", + "tags": [], + "label": "ContextProviderOpts", + "description": [ + "\nDefinition of a context provider" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ContextProviderOpts", + "text": "ContextProviderOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ContextProviderOpts.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nThe name of the provider." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ContextProviderOpts.context$", + "type": "Object", + "tags": [], + "label": "context$", + "description": [ + "\nObservable that emits the custom context." + ], + "signature": [ + "Observable", + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ContextProviderOpts.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [ + "\nSchema declaring and documenting the expected output in the context$\n" + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ShipperOptions", + "type": "Interface", + "tags": [], + "label": "ElasticV3ShipperOptions", + "description": [ + "\nOptions for the Elastic V3 shipper" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/common/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ShipperOptions.channelName", + "type": "string", + "tags": [], + "label": "channelName", + "description": [ + "\nThe name of the channel to stream all the events to." + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/common/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ShipperOptions.version", + "type": "string", + "tags": [], + "label": "version", + "description": [ + "\nThe product's version." + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/common/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ShipperOptions.sendTo", + "type": "CompoundType", + "tags": [], + "label": "sendTo", + "description": [ + "\nProvide it to override the Analytics client's default configuration." + ], + "signature": [ + "\"production\" | \"staging\" | undefined" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/common/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ElasticV3ShipperOptions.debug", + "type": "CompoundType", + "tags": [], + "label": "debug", + "description": [ + "\nShould show debug information about the requests it makes to the V3 API." + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/analytics/ebt/shippers/elastic_v3/common/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.Event", + "type": "Interface", + "tags": [], + "label": "Event", + "description": [ + "\nDefinition of the full event structure" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.Event.timestamp", + "type": "string", + "tags": [], + "label": "timestamp", + "description": [ + "\nThe time the event was generated in ISO format." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.Event.event_type", + "type": "string", + "tags": [], + "label": "event_type", + "description": [ + "\nThe event type." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.Event.properties", + "type": "Uncategorized", + "tags": [], + "label": "properties", + "description": [ + "\nThe specific properties of the event type." + ], + "signature": [ + "Properties" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.Event.context", + "type": "Object", + "tags": [], + "label": "context", + "description": [ + "\nThe {@link EventContext} enriched during the processing pipeline." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + } + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext", + "type": "Interface", + "tags": [], + "label": "EventContext", + "description": [ + "\nDefinition of the context that can be appended to the events through the {@link IAnalyticsClient.registerContextProvider}." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.cluster_uuid", + "type": "string", + "tags": [], + "label": "cluster_uuid", + "description": [ + "\nThe UUID of the cluster" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.cluster_name", + "type": "string", + "tags": [], + "label": "cluster_name", + "description": [ + "\nThe name of the cluster." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.license_id", + "type": "string", + "tags": [], + "label": "license_id", + "description": [ + "\nThe license ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.userId", + "type": "string", + "tags": [], + "label": "userId", + "description": [ + "\nThe unique user ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.cloudId", + "type": "string", + "tags": [], + "label": "cloudId", + "description": [ + "\nThe Cloud ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.isElasticCloudUser", + "type": "CompoundType", + "tags": [], + "label": "isElasticCloudUser", + "description": [ + "\n`true` if the user is logged in via the Elastic Cloud authentication provider." + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.version", + "type": "string", + "tags": [], + "label": "version", + "description": [ + "\nThe product's version." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.pageName", + "type": "string", + "tags": [], + "label": "pageName", + "description": [ + "\nThe name of the current page." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.applicationId", + "type": "string", + "tags": [], + "label": "applicationId", + "description": [ + "\nThe current application ID." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.entityId", + "type": "string", + "tags": [], + "label": "entityId", + "description": [ + "\nThe current entity ID (dashboard ID, visualization ID, etc.)." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventContext.Unnamed", + "type": "IndexSignature", + "tags": [], + "label": "[key: string]: unknown", + "description": [ + "\nAdditional keys are allowed." + ], + "signature": [ + "[key: string]: unknown" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventTypeOpts", + "type": "Interface", + "tags": [], + "label": "EventTypeOpts", + "description": [ + "\nDefinition of an Event Type." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventTypeOpts", + "text": "EventTypeOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventTypeOpts.eventType", + "type": "string", + "tags": [], + "label": "eventType", + "description": [ + "\nThe event type's unique name." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventTypeOpts.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [ + "\nSchema declaring and documenting the expected structure of this event type.\n" + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipperConfig", + "type": "Interface", + "tags": [], + "label": "FullStoryShipperConfig", + "description": [ + "\nFullStory shipper configuration." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.FullStoryShipperConfig", + "text": "FullStoryShipperConfig" + }, + " extends ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.FullStorySnippetConfig", + "text": "FullStorySnippetConfig" + } + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipperConfig.eventTypesAllowlist", + "type": "Array", + "tags": [], + "label": "eventTypesAllowlist", + "description": [ + "\nFullStory's custom events rate limit is very aggressive.\nIf this setting is provided, it'll only send the event types specified in this list." + ], + "signature": [ + "string[] | undefined" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStoryShipperConfig.pageVarsDebounceTimeMs", + "type": "number", + "tags": [], + "label": "pageVarsDebounceTimeMs", + "description": [ + "\nFullStory only allows calling setVars('page') once per navigation.\nThis setting defines how much time to hold from calling the API while additional lazy context is being resolved." + ], + "signature": [ + "number | undefined" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/fullstory_shipper.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStorySnippetConfig", + "type": "Interface", + "tags": [], + "label": "FullStorySnippetConfig", + "description": [ + "\nFullStory basic configuration." + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStorySnippetConfig.fullStoryOrgId", + "type": "string", + "tags": [], + "label": "fullStoryOrgId", + "description": [ + "\nThe FullStory account id." + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStorySnippetConfig.host", + "type": "string", + "tags": [], + "label": "host", + "description": [ + "\nThe host to send the data to. Used to overcome AdBlockers by using custom DNSs.\nIf not specified, it defaults to `fullstory.com`." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStorySnippetConfig.scriptUrl", + "type": "string", + "tags": [], + "label": "scriptUrl", + "description": [ + "\nThe URL to load the FullStory client from. Falls back to `edge.fullstory.com/s/fs.js` if not specified." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStorySnippetConfig.debug", + "type": "CompoundType", + "tags": [], + "label": "debug", + "description": [ + "\nWhether the debug logs should be printed to the console." + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.FullStorySnippetConfig.namespace", + "type": "string", + "tags": [], + "label": "namespace", + "description": [ + "\nThe name of the variable where the API is stored: `window[namespace]`. Defaults to `FS`." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/analytics/ebt/shippers/fullstory/src/load_snippet.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient", + "type": "Interface", + "tags": [], + "label": "IAnalyticsClient", + "description": [ + "\nAnalytics client's public APIs" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.reportEvent", + "type": "Function", + "tags": [ + "track-adoption" + ], + "label": "reportEvent", + "description": [ + "\nReports a telemetry event." + ], + "signature": [ + "(eventType: string, eventData: EventTypeData) => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": true, + "references": [ + { + "plugin": "@kbn/core-notifications-browser-internal", + "path": "packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_reporter.ts" + }, + { + "plugin": "@kbn/core-notifications-browser-internal", + "path": "packages/core/notifications/core-notifications-browser-internal/src/toasts/telemetry/event_reporter.ts" + }, + { + "plugin": "@kbn/ebt-tools", + "path": "packages/kbn-ebt-tools/src/performance_metric_events/helpers.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-root-server-internal", + "path": "packages/core/root/core-root-server-internal/src/events/kibana_started.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.ts" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "@kbn/cloud", + "path": "packages/cloud/connection_details/kibana/kibana_connection_details_provider.tsx" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/analytics/types.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/analytics/analytics_service.ts" + }, + { + "plugin": "observabilityAIAssistant", + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/server/utils/recall/recall_and_score.ts" + }, + { + "plugin": "observabilityAIAssistant", + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "fleet", + "path": "x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts" + }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" + }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" + }, + { + "plugin": "globalSearchBar", + "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" + }, + { + "plugin": "globalSearchBar", + "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "osquery", + "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts" + }, + { + "plugin": "reporting", + "path": "x-pack/plugins/reporting/server/usage/event_tracker.ts" + }, + { + "plugin": "searchPlayground", + "path": "x-pack/plugins/search_playground/server/routes.ts" + }, + { + "plugin": "securitySolutionServerless", + "path": "x-pack/plugins/security_solution_serverless/server/task_manager/nlp_cleanup_task/nlp_cleanup_task.ts" + }, + { + "plugin": "securitySolutionServerless", + "path": "x-pack/plugins/security_solution_serverless/server/task_manager/nlp_cleanup_task/nlp_cleanup_task.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/public/services/telemetry/telemetry_client.ts" + }, + { + "plugin": "observabilityLogsExplorer", + "path": "x-pack/plugins/observability_solution/observability_logs_explorer/public/state_machines/observability_logs_explorer/src/telemetry_events.ts" + }, + { + "plugin": "observabilityOnboarding", + "path": "x-pack/plugins/observability_solution/observability_onboarding/public/hooks/use_flow_progress_telemetry.ts" + }, + { + "plugin": "observabilityOnboarding", + "path": "x-pack/plugins/observability_solution/observability_onboarding/public/application/app.tsx" + }, + { + "plugin": "observabilityAIAssistant", + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/service/create_chat_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-mocks", + "path": "packages/core/analytics/core-analytics-browser-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/tasks/risk_scoring_task.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-mocks", + "path": "packages/core/analytics/core-analytics-browser-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/public/services/analytics/analytics.stub.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-root-browser-internal", + "path": "packages/core/root/core-root-browser-internal/src/core_system.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/server/analytics/analytics_service.test.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_clicks.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts" + } + ], + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.reportEvent.$1", + "type": "string", + "tags": [], + "label": "eventType", + "description": [ + "The event type registered via the `registerEventType` API." + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.reportEvent.$2", + "type": "Uncategorized", + "tags": [], + "label": "eventData", + "description": [ + "The properties matching the schema declared in the `registerEventType` API." + ], + "signature": [ + "EventTypeData" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.registerEventType", + "type": "Function", + "tags": [], + "label": "registerEventType", + "description": [ + "\nRegisters the event type that will be emitted via the reportEvent API." + ], + "signature": [ + "(eventTypeOps: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventTypeOpts", + "text": "EventTypeOpts" + }, + ") => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.registerEventType.$1", + "type": "Object", + "tags": [], + "label": "eventTypeOps", + "description": [ + "The definition of the event type {@link EventTypeOpts }." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventTypeOpts", + "text": "EventTypeOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.registerShipper", + "type": "Function", + "tags": [], + "label": "registerShipper", + "description": [ + "\nSet up the shipper that will be used to report the telemetry events." + ], + "signature": [ + "(Shipper: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ShipperClassConstructor", + "text": "ShipperClassConstructor" + }, + ", shipperConfig: ShipperConfig, opts?: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.RegisterShipperOpts", + "text": "RegisterShipperOpts" + }, + " | undefined) => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.registerShipper.$1", + "type": "Object", + "tags": [], + "label": "Shipper", + "description": [ + "The {@link IShipper } class to instantiate the shipper." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ShipperClassConstructor", + "text": "ShipperClassConstructor" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.registerShipper.$2", + "type": "Uncategorized", + "tags": [], + "label": "shipperConfig", + "description": [ + "The config specific to the Shipper to instantiate." + ], + "signature": [ + "ShipperConfig" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.registerShipper.$3", + "type": "Object", + "tags": [], + "label": "opts", + "description": [ + "Additional options to register the shipper {@link RegisterShipperOpts }." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.RegisterShipperOpts", + "text": "RegisterShipperOpts" + }, + " | undefined" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nUsed to control the user's consent to report the data.\nIn the advanced mode, it allows to \"cherry-pick\" which events and shippers are enabled/disabled." + ], + "signature": [ + "(optInConfig: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.OptInConfig", + "text": "OptInConfig" + }, + ") => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.optIn.$1", + "type": "Object", + "tags": [], + "label": "optInConfig", + "description": [ + "{@link OptInConfig }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.OptInConfig", + "text": "OptInConfig" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.registerContextProvider", + "type": "Function", + "tags": [ + "track-adoption" + ], + "label": "registerContextProvider", + "description": [ + "\nRegisters the context provider to enrich any reported events." + ], + "signature": [ + "(contextProviderOpts: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ContextProviderOpts", + "text": "ContextProviderOpts" + }, + ") => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": true, + "references": [ + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.ts" + }, + { + "plugin": "@kbn/core-elasticsearch-server-internal", + "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/register_analytics_context_provider.ts" + }, + { + "plugin": "@kbn/core-environment-server-internal", + "path": "packages/core/environment/core-environment-server-internal/src/environment_service.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-plugins-server-internal", + "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts" + }, + { + "plugin": "cloud", + "path": "x-pack/plugins/cloud/common/register_cloud_deployment_id_analytics_context.ts" + }, + { + "plugin": "licensing", + "path": "x-pack/plugins/licensing/common/register_analytics_context_provider.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.ts" + }, + { + "plugin": "telemetry", + "path": "src/plugins/telemetry/server/plugin.ts" + }, + { + "plugin": "telemetry", + "path": "src/plugins/telemetry/public/plugin.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-mocks", + "path": "packages/core/analytics/core-analytics-browser-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/analytics_service.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-application-browser-internal", + "path": "packages/core/application/core-application-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-chrome-browser-internal", + "path": "packages/core/chrome/core-chrome-browser-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.test.ts" + }, + { + "plugin": "@kbn/core-execution-context-browser-internal", + "path": "packages/core/execution-context/core-execution-context-browser-internal/src/execution_context_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-analytics-server-mocks", + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts" + }, + { + "plugin": "@kbn/core-elasticsearch-server-internal", + "path": "packages/core/elasticsearch/core-elasticsearch-server-internal/src/register_analytics_context_provider.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-status-server-internal", + "path": "packages/core/status/core-status-server-internal/src/status_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/analytics_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-browser-internal", + "path": "packages/core/analytics/core-analytics-browser-internal/src/track_viewport_size.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.mocks.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.ts" + }, + { + "plugin": "@kbn/core-analytics-server-internal", + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.test.ts" + } + ], + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.registerContextProvider.$1", + "type": "Object", + "tags": [], + "label": "contextProviderOpts", + "description": [ + "{@link ContextProviderOpts }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ContextProviderOpts", + "text": "ContextProviderOpts" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.removeContextProvider", + "type": "Function", + "tags": [], + "label": "removeContextProvider", + "description": [ + "\nRemoves the context provider and stop enriching the events from its context." + ], + "signature": [ + "(contextProviderName: string) => void" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.removeContextProvider.$1", + "type": "string", + "tags": [], + "label": "contextProviderName", + "description": [ + "The name of the context provider to remove." + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.telemetryCounter$", + "type": "Object", + "tags": [], + "label": "telemetryCounter$", + "description": [ + "\nObservable to emit the stats of the processed events." + ], + "signature": [ + "Observable", + "<", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.TelemetryCounter", + "text": "TelemetryCounter" + }, + ">" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nForces all shippers to send all their enqueued events and fulfills the returned promise." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IAnalyticsClient.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nStops the client. Flushing any pending events in the process." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper", + "type": "Interface", + "tags": [], + "label": "IShipper", + "description": [ + "\nBasic structure of a Shipper" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper.reportEvents", + "type": "Function", + "tags": [], + "label": "reportEvents", + "description": [ + "\nAdapts and ships the event to the persisting/analytics solution." + ], + "signature": [ + "(events: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]) => void" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper.reportEvents.$1", + "type": "Array", + "tags": [], + "label": "events", + "description": [ + "batched events {@link Event }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.Event", + "text": "Event" + }, + ">[]" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper.optIn", + "type": "Function", + "tags": [], + "label": "optIn", + "description": [ + "\nStops/restarts the shipping mechanism based on the value of isOptedIn" + ], + "signature": [ + "(isOptedIn: boolean) => void" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper.optIn.$1", + "type": "boolean", + "tags": [], + "label": "isOptedIn", + "description": [ + "`true` for resume sending events. `false` to stop." + ], + "signature": [ + "boolean" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper.extendContext", + "type": "Function", + "tags": [], + "label": "extendContext", + "description": [ + "\nPerform any necessary calls to the persisting/analytics solution to set the event's context." + ], + "signature": [ + "((newContext: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + }, + ") => void) | undefined" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper.extendContext.$1", + "type": "Object", + "tags": [], + "label": "newContext", + "description": [ + "The full new context to set {@link EventContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.EventContext", + "text": "EventContext" + } + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper.telemetryCounter$", + "type": "Object", + "tags": [], + "label": "telemetryCounter$", + "description": [ + "\nObservable to emit the stats of the processed events." + ], + "signature": [ + "Observable", + "<", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.TelemetryCounter", + "text": "TelemetryCounter" + }, + "> | undefined" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper.flush", + "type": "Function", + "tags": [], + "label": "flush", + "description": [ + "\nSends all the enqueued events and fulfills the returned promise." + ], + "signature": [ + "() => Promise" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.IShipper.shutdown", + "type": "Function", + "tags": [], + "label": "shutdown", + "description": [ + "\nShutdown the shipper." + ], + "signature": [ + "() => void" + ], + "path": "packages/analytics/ebt/client/src/shippers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.OptInConfig", + "type": "Interface", + "tags": [], + "label": "OptInConfig", + "description": [ + "\nOptions for the optIn API" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.OptInConfig.global", + "type": "Object", + "tags": [], + "label": "global", + "description": [ + "\nControls the global enabled/disabled behaviour of the client and shippers." + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.OptInConfigPerType", + "text": "OptInConfigPerType" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.OptInConfig.event_types", + "type": "Object", + "tags": [], + "label": "event_types", + "description": [ + "\nControls if an event type should be disabled for a specific type of shipper." + ], + "signature": [ + "Record | undefined" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.OptInConfigPerType", + "type": "Interface", + "tags": [], + "label": "OptInConfigPerType", + "description": [ + "\nSets whether a type of event is enabled/disabled globally or per shipper." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.OptInConfigPerType.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [ + "\nThe event type is globally enabled." + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.OptInConfigPerType.shippers", + "type": "Object", + "tags": [], + "label": "shippers", + "description": [ + "\nControls if an event type should be disabled for a specific type of shipper." + ], + "signature": [ + "Record | undefined" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.RegisterShipperOpts", + "type": "Interface", + "tags": [], + "label": "RegisterShipperOpts", + "description": [ + "\nOptional options to register a shipper" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaArray", + "type": "Interface", + "tags": [], + "label": "SchemaArray", + "description": [ + "\nSchema to represent an array" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " extends ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMeta", + "text": "SchemaMeta" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaArray.type", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "The type must be an array" + ], + "signature": [ + "\"array\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaArray.items", + "type": "CompoundType", + "tags": [], + "label": "items", + "description": [ + "The schema of the items in the array is defined in the `items` property" + ], + "signature": [ + "{ type: \"pass_through\"; _meta: { description: string; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + "; } | (unknown extends Value ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends (infer U)[] | readonly (infer U)[] ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " : NonNullable extends Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends object ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + ")" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaChildValue", + "type": "Interface", + "tags": [], + "label": "SchemaChildValue", + "description": [ + "\nSchema to define a primitive value" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaChildValue.type", + "type": "Uncategorized", + "tags": [], + "label": "type", + "description": [ + "The type of the value" + ], + "signature": [ + "NonNullable extends string | Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaStringTypes", + "text": "AllowedSchemaStringTypes" + }, + " : NonNullable extends number ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaNumberTypes", + "text": "AllowedSchemaNumberTypes" + }, + " : NonNullable extends boolean ? \"boolean\" : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaTypes", + "text": "AllowedSchemaTypes" + } + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaChildValue._meta", + "type": "CompoundType", + "tags": [], + "label": "_meta", + "description": [ + "Meta properties of the value: description and is optional" + ], + "signature": [ + "{ description: string; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaMeta", + "type": "Interface", + "tags": [], + "label": "SchemaMeta", + "description": [ + "\nSchema meta with optional description" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMeta", + "text": "SchemaMeta" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaMeta._meta", + "type": "CompoundType", + "tags": [], + "label": "_meta", + "description": [ + "Meta properties of the pass through: description and is optional" + ], + "signature": [ + "({ description?: string | undefined; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + ") | undefined" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaObject", + "type": "Interface", + "tags": [], + "label": "SchemaObject", + "description": [ + "\nSchema to represent an object" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " extends ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMeta", + "text": "SchemaMeta" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaObject.properties", + "type": "Object", + "tags": [], + "label": "properties", + "description": [ + "\nThe schemas of the keys of the object are defined in the `properties` object." + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ShipperClassConstructor", + "type": "Interface", + "tags": [], + "label": "ShipperClassConstructor", + "description": [ + "\nConstructor of a {@link IShipper}" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.ShipperClassConstructor", + "text": "ShipperClassConstructor" + }, + "" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ShipperClassConstructor.shipperName", + "type": "string", + "tags": [], + "label": "shipperName", + "description": [ + "\nThe shipper's unique name" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ShipperClassConstructor.new", + "type": "Function", + "tags": [], + "label": "new", + "description": [ + "\nThe constructor" + ], + "signature": [ + "any" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ShipperClassConstructor.new.$1", + "type": "Uncategorized", + "tags": [], + "label": "config", + "description": [ + "The shipper's custom config" + ], + "signature": [ + "Config" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ShipperClassConstructor.new.$2", + "type": "Object", + "tags": [], + "label": "initContext", + "description": [ + "Common context {@link AnalyticsClientInitContext }" + ], + "signature": [ + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AnalyticsClientInitContext", + "text": "AnalyticsClientInitContext" + } + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.TelemetryCounter", + "type": "Interface", + "tags": [], + "label": "TelemetryCounter", + "description": [ + "\nShape of the events emitted by the telemetryCounter$ observable" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.TelemetryCounter.type", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [ + "\n{@link TelemetryCounterType}" + ], + "signature": [ + "\"succeeded\" | \"failed\" | \"enqueued\" | \"sent_to_shipper\" | \"dropped\"" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.TelemetryCounter.source", + "type": "string", + "tags": [], + "label": "source", + "description": [ + "\nWho emitted the event? It can be \"client\" or the name of the shipper." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.TelemetryCounter.event_type", + "type": "string", + "tags": [], + "label": "event_type", + "description": [ + "\nThe event type the success/failure/drop event refers to." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.TelemetryCounter.code", + "type": "string", + "tags": [], + "label": "code", + "description": [ + "\nCode to provide additional information about the success or failure. Examples are 200/400/504/ValidationError/UnknownError" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.TelemetryCounter.count", + "type": "number", + "tags": [], + "label": "count", + "description": [ + "\nThe number of events that this counter refers to." + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.AllowedSchemaBooleanTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaBooleanTypes", + "description": [ + "Types matching boolean values" + ], + "signature": [ + "\"boolean\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.AllowedSchemaNumberTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaNumberTypes", + "description": [ + "Types matching number values" + ], + "signature": [ + "\"date\" | \"integer\" | \"long\" | \"short\" | \"byte\" | \"float\" | \"double\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.AllowedSchemaStringTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaStringTypes", + "description": [ + "Types matching string values" + ], + "signature": [ + "\"keyword\" | \"text\" | \"date\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.AllowedSchemaTypes", + "type": "Type", + "tags": [], + "label": "AllowedSchemaTypes", + "description": [ + "\nPossible type values in the schema" + ], + "signature": [ + "\"boolean\" | \"keyword\" | \"text\" | \"date\" | \"integer\" | \"long\" | \"short\" | \"byte\" | \"float\" | \"double\"" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ContextProviderName", + "type": "Type", + "tags": [], + "label": "ContextProviderName", + "description": [ + "\nContextProviderName used for indexed structures. Only used to improve the readability of the types" + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.EventType", + "type": "Type", + "tags": [], + "label": "EventType", + "description": [ + "\nEvent Type used for indexed structures. Only used to improve the readability of the types" + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.PossibleSchemaTypes", + "type": "Type", + "tags": [], + "label": "PossibleSchemaTypes", + "description": [ + "\nHelper to ensure the declared types match the schema types" + ], + "signature": [ + "Value extends string | Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaStringTypes", + "text": "AllowedSchemaStringTypes" + }, + " : Value extends number ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaNumberTypes", + "text": "AllowedSchemaNumberTypes" + }, + " : Value extends boolean ? \"boolean\" : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.AllowedSchemaTypes", + "text": "AllowedSchemaTypes" + } + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.RootSchema", + "type": "Type", + "tags": [], + "label": "RootSchema", + "description": [ + "\nSchema definition to match the structure of the properties provided.\n" + ], + "signature": [ + "{ [Key in keyof Required]: ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaValue", + "text": "SchemaValue" + }, + "; }" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaMetaOptional", + "type": "Type", + "tags": [], + "label": "SchemaMetaOptional", + "description": [ + "\nEnforces { optional: true } if the value can be undefined" + ], + "signature": [ + "unknown extends Value ? { optional?: boolean | undefined; } : undefined extends Value ? { optional: true; } : { optional?: false | undefined; }" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.SchemaValue", + "type": "Type", + "tags": [], + "label": "SchemaValue", + "description": [ + "\nType that defines all the possible values that the Schema accepts.\nThese types definitions are helping to identify earlier the possible missing `properties` nesting when\nmanually defining the schemas." + ], + "signature": [ + "{ type: \"pass_through\"; _meta: { description: string; } & ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaMetaOptional", + "text": "SchemaMetaOptional" + }, + "; } | (unknown extends Value ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " | ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends (infer U)[] | readonly (infer U)[] ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaArray", + "text": "SchemaArray" + }, + " : NonNullable extends Date ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + " : NonNullable extends object ? ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaObject", + "text": "SchemaObject" + }, + " : ", + { + "pluginId": "@kbn/ebt", + "scope": "common", + "docId": "kibKbnEbtPluginApi", + "section": "def-common.SchemaChildValue", + "text": "SchemaChildValue" + }, + ")" + ], + "path": "packages/analytics/ebt/client/src/schema/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.ShipperName", + "type": "Type", + "tags": [], + "label": "ShipperName", + "description": [ + "\nShipper Name used for indexed structures. Only used to improve the readability of the types" + ], + "signature": [ + "string" + ], + "path": "packages/analytics/ebt/client/src/analytics_client/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ebt", + "id": "def-common.TelemetryCounterType", + "type": "Type", + "tags": [], + "label": "TelemetryCounterType", + "description": [ + "\nIndicates if the event contains data about succeeded, failed or dropped events:\n- enqueued: The event was accepted and will be sent to the shippers when they become available (and opt-in === true).\n- sent_to_shipper: The event was sent to at least one shipper.\n- succeeded: The event was successfully sent by the shipper.\n- failed: There was an error when processing/shipping the event. Refer to the Telemetry Counter's code for the reason.\n- dropped: The event was dropped from the queue. Refer to the Telemetry Counter's code for the reason." + ], + "signature": [ + "\"succeeded\" | \"failed\" | \"enqueued\" | \"sent_to_shipper\" | \"dropped\"" + ], + "path": "packages/analytics/ebt/client/src/events/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_ebt.mdx b/api_docs/kbn_ebt.mdx new file mode 100644 index 00000000000000..eff48712195b2a --- /dev/null +++ b/api_docs/kbn_ebt.mdx @@ -0,0 +1,36 @@ +--- +#### +#### 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. +#### +id: kibKbnEbtPluginApi +slug: /kibana-dev-docs/api/kbn-ebt +title: "@kbn/ebt" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/ebt plugin +date: 2024-06-19 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt'] +--- +import kbnEbtObj from './kbn_ebt.devdocs.json'; + + + +Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 152 | 0 | 0 | 0 | + +## Common + +### Classes + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_ebt_tools.devdocs.json b/api_docs/kbn_ebt_tools.devdocs.json index ed143ac7aeec19..44363fefececf2 100644 --- a/api_docs/kbn_ebt_tools.devdocs.json +++ b/api_docs/kbn_ebt_tools.devdocs.json @@ -65,9 +65,9 @@ "signature": [ "(analytics: Pick<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.IAnalyticsClient", "text": "IAnalyticsClient" }, @@ -89,9 +89,9 @@ "signature": [ "Pick<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.IAnalyticsClient", "text": "IAnalyticsClient" }, @@ -118,9 +118,9 @@ "signature": [ "(analytics: Pick<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.IAnalyticsClient", "text": "IAnalyticsClient" }, @@ -150,9 +150,9 @@ "signature": [ "Pick<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.IAnalyticsClient", "text": "IAnalyticsClient" }, diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index ef632ce1a693c9..ecb6ea6043d715 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index 6d0bfdecc32145..3966867b26154c 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_agent_utils.mdx b/api_docs/kbn_elastic_agent_utils.mdx index 389bd6dfbcb13e..bc3aade98a916e 100644 --- a/api_docs/kbn_elastic_agent_utils.mdx +++ b/api_docs/kbn_elastic_agent_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-agent-utils title: "@kbn/elastic-agent-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-agent-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 822df19b8e86fa..376443426f3dbc 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant_common.devdocs.json b/api_docs/kbn_elastic_assistant_common.devdocs.json index 99c152889d5a3a..7f5b1cccc87809 100644 --- a/api_docs/kbn_elastic_assistant_common.devdocs.json +++ b/api_docs/kbn_elastic_assistant_common.devdocs.json @@ -1607,6 +1607,18 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_FIND", + "type": "string", + "tags": [], + "label": "ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_FIND", + "description": [], + "path": "x-pack/packages/kbn-elastic-assistant-common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL", @@ -1880,6 +1892,81 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.FindKnowledgeBaseEntriesRequestQuery", + "type": "Type", + "tags": [], + "label": "FindKnowledgeBaseEntriesRequestQuery", + "description": [], + "signature": [ + "{ per_page: number; page: number; fields?: string[] | undefined; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.FindKnowledgeBaseEntriesRequestQueryInput", + "type": "Type", + "tags": [], + "label": "FindKnowledgeBaseEntriesRequestQueryInput", + "description": [], + "signature": [ + "{ fields?: unknown; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; page?: number | undefined; per_page?: number | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.FindKnowledgeBaseEntriesResponse", + "type": "Type", + "tags": [], + "label": "FindKnowledgeBaseEntriesResponse", + "description": [], + "signature": [ + "{ page: number; perPage: number; total: number; data: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.FindKnowledgeBaseEntriesSortField", + "type": "Type", + "tags": [], + "label": "FindKnowledgeBaseEntriesSortField", + "description": [], + "signature": [ + "\"title\" | \"updated_at\" | \"created_at\" | \"is_default\"" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.FindKnowledgeBaseEntriesSortFieldEnum", + "type": "Type", + "tags": [], + "label": "FindKnowledgeBaseEntriesSortFieldEnum", + "description": [], + "signature": [ + "{ title: \"title\"; updated_at: \"updated_at\"; created_at: \"created_at\"; is_default: \"is_default\"; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.GetCapabilitiesResponse", @@ -2639,7 +2726,7 @@ "signature": [ "\"asc\" | \"desc\"" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -2654,7 +2741,7 @@ "signature": [ "{ asc: \"asc\"; desc: \"desc\"; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -3663,6 +3750,66 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.FindKnowledgeBaseEntriesRequestQuery", + "type": "Object", + "tags": [], + "label": "FindKnowledgeBaseEntriesRequestQuery", + "description": [], + "signature": [ + "Zod.ZodObject<{ fields: Zod.ZodOptional, string[], unknown>>; filter: Zod.ZodOptional; sort_field: Zod.ZodOptional>; sort_order: Zod.ZodOptional>; page: Zod.ZodDefault>; per_page: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { per_page: number; page: number; fields?: string[] | undefined; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; }, { fields?: unknown; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; page?: number | undefined; per_page?: number | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.FindKnowledgeBaseEntriesResponse", + "type": "Object", + "tags": [], + "label": "FindKnowledgeBaseEntriesResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ page: Zod.ZodNumber; perPage: Zod.ZodNumber; total: Zod.ZodNumber; data: Zod.ZodArray; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { page: number; perPage: number; total: number; data: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; }, { page: number; perPage: number; total: number; data: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.FindKnowledgeBaseEntriesSortField", + "type": "Object", + "tags": [], + "label": "FindKnowledgeBaseEntriesSortField", + "description": [], + "signature": [ + "Zod.ZodEnum<[\"created_at\", \"is_default\", \"title\", \"updated_at\"]>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.FindKnowledgeBaseEntriesSortFieldEnum", + "type": "Object", + "tags": [], + "label": "FindKnowledgeBaseEntriesSortFieldEnum", + "description": [], + "signature": [ + "{ title: \"title\"; updated_at: \"updated_at\"; created_at: \"created_at\"; is_default: \"is_default\"; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/find_knowledge_base_entries_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.GetCapabilitiesResponse", @@ -4273,7 +4420,7 @@ "signature": [ "Zod.ZodEnum<[\"asc\", \"desc\"]>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -4288,7 +4435,7 @@ "signature": [ "{ asc: \"asc\"; desc: \"desc\"; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index 9e4c31025175de..8c2dc5cdf2b7cd 100644 --- a/api_docs/kbn_elastic_assistant_common.mdx +++ b/api_docs/kbn_elastic_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant-common title: "@kbn/elastic-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 295 | 0 | 276 | 0 | +| 305 | 0 | 286 | 0 | ## Common diff --git a/api_docs/kbn_entities_schema.mdx b/api_docs/kbn_entities_schema.mdx index 198cfcc01bac47..68ab25caaed791 100644 --- a/api_docs/kbn_entities_schema.mdx +++ b/api_docs/kbn_entities_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-entities-schema title: "@kbn/entities-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/entities-schema plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/entities-schema'] --- import kbnEntitiesSchemaObj from './kbn_entities_schema.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index 34e75530265261..1065242e2ce20e 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index fcd3764151fb15..534d4fed39a369 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index a3c7ca961734e8..4900cf0b98c7c4 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index e952e747c1c0d3..1b19fa053acc11 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index f02fa1ee652b9d..feb5fad5b90425 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 1ea8516125ece9..47d8c928be47e1 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_esql_ast.devdocs.json b/api_docs/kbn_esql_ast.devdocs.json index 870bb8da9db783..8449e60698bff3 100644 --- a/api_docs/kbn_esql_ast.devdocs.json +++ b/api_docs/kbn_esql_ast.devdocs.json @@ -1302,7 +1302,19 @@ "docId": "kibKbnEsqlAstPluginApi", "section": "def-common.ESQLCommandMode", "text": "ESQLCommandMode" - } + }, + " | ", + "ESQLInlineCast", + "<", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLAstItem", + "text": "ESQLAstItem" + }, + "> | ", + "ESQLUnknownItem" ], "path": "packages/kbn-esql-ast/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_esql_ast.mdx b/api_docs/kbn_esql_ast.mdx index df1043fcfa395e..2a28cd4a0e37a1 100644 --- a/api_docs/kbn_esql_ast.mdx +++ b/api_docs/kbn_esql_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-ast title: "@kbn/esql-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-ast plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-ast'] --- import kbnEsqlAstObj from './kbn_esql_ast.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 68 | 1 | 68 | 7 | +| 68 | 1 | 68 | 9 | ## Common diff --git a/api_docs/kbn_esql_utils.mdx b/api_docs/kbn_esql_utils.mdx index 821d90db7c9a31..05bc1416a8a733 100644 --- a/api_docs/kbn_esql_utils.mdx +++ b/api_docs/kbn_esql_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-utils title: "@kbn/esql-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-utils'] --- import kbnEsqlUtilsObj from './kbn_esql_utils.devdocs.json'; diff --git a/api_docs/kbn_esql_validation_autocomplete.devdocs.json b/api_docs/kbn_esql_validation_autocomplete.devdocs.json index 75d1a0843c4989..ea46ea3ba35dab 100644 --- a/api_docs/kbn_esql_validation_autocomplete.devdocs.json +++ b/api_docs/kbn_esql_validation_autocomplete.devdocs.json @@ -19,6 +19,106 @@ "common": { "classes": [], "functions": [ + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.checkFunctionArgMatchesDefinition", + "type": "Function", + "tags": [], + "label": "checkFunctionArgMatchesDefinition", + "description": [ + "\nChecks if an AST function argument is of the correct type\ngiven the definition." + ], + "signature": [ + "(arg: ", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLSingleAstItem", + "text": "ESQLSingleAstItem" + }, + ", parameterDefinition: { name: string; type: ", + "FunctionParameterType", + "; optional?: boolean | undefined; noNestingFunctions?: boolean | undefined; supportsWildcard?: boolean | undefined; constantOnly?: boolean | undefined; literalOptions?: string[] | undefined; literalSuggestions?: string[] | undefined; }, references: ", + "ReferenceMaps", + ", parentCommand: string | undefined) => boolean | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.checkFunctionArgMatchesDefinition.$1", + "type": "CompoundType", + "tags": [], + "label": "arg", + "description": [], + "signature": [ + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLSingleAstItem", + "text": "ESQLSingleAstItem" + } + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.checkFunctionArgMatchesDefinition.$2", + "type": "Object", + "tags": [], + "label": "parameterDefinition", + "description": [], + "signature": [ + "{ name: string; type: ", + "FunctionParameterType", + "; optional?: boolean | undefined; noNestingFunctions?: boolean | undefined; supportsWildcard?: boolean | undefined; constantOnly?: boolean | undefined; literalOptions?: string[] | undefined; literalSuggestions?: string[] | undefined; }" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.checkFunctionArgMatchesDefinition.$3", + "type": "Object", + "tags": [], + "label": "references", + "description": [], + "signature": [ + "ReferenceMaps" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.checkFunctionArgMatchesDefinition.$4", + "type": "string", + "tags": [], + "label": "parentCommand", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.collectVariables", @@ -121,72 +221,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.columnExists", - "type": "Function", - "tags": [], - "label": "columnExists", - "description": [], - "signature": [ - "(column: ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLColumn", - "text": "ESQLColumn" - }, - ", { fields, variables }: Pick<", - "ReferenceMaps", - ", \"fields\" | \"variables\">) => { hit: boolean; nameHit: string; } | { hit: boolean; nameHit?: undefined; }" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.columnExists.$1", - "type": "Object", - "tags": [], - "label": "column", - "description": [], - "signature": [ - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLColumn", - "text": "ESQLColumn" - } - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.columnExists.$2", - "type": "Object", - "tags": [], - "label": "{ fields, variables }", - "description": [], - "signature": [ - "Pick<", - "ReferenceMaps", - ", \"fields\" | \"variables\">" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.getActions", @@ -601,6 +635,18 @@ "section": "def-common.ESQLCommandMode", "text": "ESQLCommandMode" }, + " | ", + "ESQLInlineCast", + "<", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLAstItem", + "text": "ESQLAstItem" + }, + "> | ", + "ESQLUnknownItem", "; option: ", { "pluginId": "@kbn/esql-ast", @@ -699,6 +745,18 @@ "section": "def-common.ESQLCommandMode", "text": "ESQLCommandMode" }, + " | ", + "ESQLInlineCast", + "<", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLAstItem", + "text": "ESQLAstItem" + }, + "> | ", + "ESQLUnknownItem", " | undefined; option: ", { "pluginId": "@kbn/esql-ast", @@ -781,6 +839,18 @@ "section": "def-common.ESQLCommandMode", "text": "ESQLCommandMode" }, + " | ", + "ESQLInlineCast", + "<", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLAstItem", + "text": "ESQLAstItem" + }, + "> | ", + "ESQLUnknownItem", " | undefined; option: ", { "pluginId": "@kbn/esql-ast", @@ -871,6 +941,18 @@ "section": "def-common.ESQLCommandMode", "text": "ESQLCommandMode" }, + " | ", + "ESQLInlineCast", + "<", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLAstItem", + "text": "ESQLAstItem" + }, + "> | ", + "ESQLUnknownItem", " | undefined; setting: ", { "pluginId": "@kbn/esql-ast", @@ -940,89 +1022,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.getColumnHit", - "type": "Function", - "tags": [], - "label": "getColumnHit", - "description": [], - "signature": [ - "(columnName: string, { fields, variables }: Pick<", - "ReferenceMaps", - ", \"fields\" | \"variables\">, position: number | undefined) => ", - { - "pluginId": "@kbn/esql-validation-autocomplete", - "scope": "common", - "docId": "kibKbnEsqlValidationAutocompletePluginApi", - "section": "def-common.ESQLVariable", - "text": "ESQLVariable" - }, - " | ", - { - "pluginId": "@kbn/esql-validation-autocomplete", - "scope": "common", - "docId": "kibKbnEsqlValidationAutocompletePluginApi", - "section": "def-common.ESQLRealField", - "text": "ESQLRealField" - }, - " | undefined" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.getColumnHit.$1", - "type": "string", - "tags": [], - "label": "columnName", - "description": [], - "signature": [ - "string" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.getColumnHit.$2", - "type": "Object", - "tags": [], - "label": "{ fields, variables }", - "description": [], - "signature": [ - "Pick<", - "ReferenceMaps", - ", \"fields\" | \"variables\">" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.getColumnHit.$3", - "type": "number", - "tags": [], - "label": "position", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.getCommandDefinition", @@ -1353,7 +1352,7 @@ "section": "def-common.ESQLCallbacks", "text": "ESQLCallbacks" }, - " | undefined) => () => Promise<{ name: string; hidden: boolean; }[]>" + " | undefined) => () => Promise<{ name: string; hidden: boolean; title?: string | undefined; dataStreams?: { name: string; title?: string | undefined; }[] | undefined; }[]>" ], "path": "packages/kbn-esql-validation-autocomplete/src/shared/resources_helpers.ts", "deprecated": false, @@ -1527,121 +1526,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.isEqualType", - "type": "Function", - "tags": [], - "label": "isEqualType", - "description": [ - "\nChecks if an AST argument is of the correct type\ngiven the definition." - ], - "signature": [ - "(arg: ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, - ", argDef: { name: string; type: ", - "FunctionParameterType", - "; optional?: boolean | undefined; noNestingFunctions?: boolean | undefined; supportsWildcard?: boolean | undefined; constantOnly?: boolean | undefined; literalOptions?: string[] | undefined; literalSuggestions?: string[] | undefined; } | { name: string; type: string; optional?: boolean | undefined; innerType?: string | undefined; values?: string[] | undefined; valueDescriptions?: string[] | undefined; constantOnly?: boolean | undefined; wildcards?: boolean | undefined; }, references: ", - "ReferenceMaps", - ", parentCommand: string | undefined, nameHit: string | undefined) => boolean | undefined" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.isEqualType.$1", - "type": "CompoundType", - "tags": [], - "label": "arg", - "description": [], - "signature": [ - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - } - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.isEqualType.$2", - "type": "CompoundType", - "tags": [], - "label": "argDef", - "description": [], - "signature": [ - "{ name: string; type: ", - "FunctionParameterType", - "; optional?: boolean | undefined; noNestingFunctions?: boolean | undefined; supportsWildcard?: boolean | undefined; constantOnly?: boolean | undefined; literalOptions?: string[] | undefined; literalSuggestions?: string[] | undefined; } | { name: string; type: string; optional?: boolean | undefined; innerType?: string | undefined; values?: string[] | undefined; valueDescriptions?: string[] | undefined; constantOnly?: boolean | undefined; wildcards?: boolean | undefined; }" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.isEqualType.$3", - "type": "Object", - "tags": [], - "label": "references", - "description": [], - "signature": [ - "ReferenceMaps" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.isEqualType.$4", - "type": "string", - "tags": [], - "label": "parentCommand", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.isEqualType.$5", - "type": "string", - "tags": [], - "label": "nameHit", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.isExpression", @@ -2083,6 +1967,90 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.lookupColumn", + "type": "Function", + "tags": [], + "label": "lookupColumn", + "description": [ + "\nThis function returns the variable or field matching a column" + ], + "signature": [ + "(column: ", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLColumn", + "text": "ESQLColumn" + }, + ", { fields, variables }: Pick<", + "ReferenceMaps", + ", \"fields\" | \"variables\">) => ", + { + "pluginId": "@kbn/esql-validation-autocomplete", + "scope": "common", + "docId": "kibKbnEsqlValidationAutocompletePluginApi", + "section": "def-common.ESQLVariable", + "text": "ESQLVariable" + }, + " | ", + { + "pluginId": "@kbn/esql-validation-autocomplete", + "scope": "common", + "docId": "kibKbnEsqlValidationAutocompletePluginApi", + "section": "def-common.ESQLRealField", + "text": "ESQLRealField" + }, + " | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.lookupColumn.$1", + "type": "Object", + "tags": [], + "label": "column", + "description": [], + "signature": [ + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLColumn", + "text": "ESQLColumn" + } + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.lookupColumn.$2", + "type": "Object", + "tags": [], + "label": "{ fields, variables }", + "description": [], + "signature": [ + "Pick<", + "ReferenceMaps", + ", \"fields\" | \"variables\">" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.printFunctionSignature", @@ -2977,7 +2945,7 @@ "label": "getSources", "description": [], "signature": [ - "CallbackFn<{}, { name: string; hidden: boolean; }> | undefined" + "CallbackFn<{}, { name: string; hidden: boolean; title?: string | undefined; dataStreams?: { name: string; title?: string | undefined; }[] | undefined; }> | undefined" ], "path": "packages/kbn-esql-validation-autocomplete/src/shared/types.ts", "deprecated": false, diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index 8cf5a9051dac73..f326d93d5c638c 100644 --- a/api_docs/kbn_esql_validation_autocomplete.mdx +++ b/api_docs/kbn_esql_validation_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-validation-autocomplete title: "@kbn/esql-validation-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-validation-autocomplete plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-validation-autocomplete'] --- import kbnEsqlValidationAutocompleteObj from './kbn_esql_validation_autocomplete.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 194 | 0 | 184 | 10 | +| 189 | 0 | 178 | 10 | ## Common diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index 195dcc7f252e42..93754c21b806c8 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index cd2ffd5dc03be0..7b083d3bdcdcb7 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index ddf980c7880954..97773962b03711 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 0dbb4516f899b5..a0cab91e0732e8 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index 607e6e85b5b860..61c5a7cc45dbee 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 5c30aa57582231..516e28902c8302 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_formatters.mdx b/api_docs/kbn_formatters.mdx index 6badbde276ef97..55ad163620e2a3 100644 --- a/api_docs/kbn_formatters.mdx +++ b/api_docs/kbn_formatters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-formatters title: "@kbn/formatters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/formatters plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/formatters'] --- import kbnFormattersObj from './kbn_formatters.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 7d14b862832b89..76a7e2562c5f39 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_ui_services.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index 0816a776cc2d8d..eb5e6081a592ff 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.mdx +++ b/api_docs/kbn_ftr_common_functional_ui_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-ui-services title: "@kbn/ftr-common-functional-ui-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-ui-services plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-ui-services'] --- import kbnFtrCommonFunctionalUiServicesObj from './kbn_ftr_common_functional_ui_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 273f2e8ae97068..377d3f28132a8b 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index 6e04d34d1e580f..aeb4254520b6a4 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index 89d00a9f4726bf..0dfb7c3ed231d8 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index c58584592fe2d5..abe0caab761c9f 100644 --- a/api_docs/kbn_grouping.mdx +++ b/api_docs/kbn_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grouping title: "@kbn/grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grouping plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grouping'] --- import kbnGroupingObj from './kbn_grouping.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index f0c50d75baef50..d77bf48458c7c4 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 92086810350eaf..2b379b261a2a28 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index dc2e61157905c4..6246e2e784241d 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index 8b15c7a2519458..bd4698775dfcdf 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 2411e3232b526d..3bdc220beb3a50 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index df62efebdf0483..0fac54d1c40563 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index 00596b5b411622..1be4bfe0b0f675 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index 5b9256cbf9013e..aac51775cf05d4 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 994dc23e2cdeec..758d716f100291 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_index_management.mdx b/api_docs/kbn_index_management.mdx index 4216389c07d072..c2daabbf703aa5 100644 --- a/api_docs/kbn_index_management.mdx +++ b/api_docs/kbn_index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-management title: "@kbn/index-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-management plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-management'] --- import kbnIndexManagementObj from './kbn_index_management.devdocs.json'; diff --git a/api_docs/kbn_inference_integration_flyout.mdx b/api_docs/kbn_inference_integration_flyout.mdx index 2fd7b7701b5a5a..95cae23bb1c3f5 100644 --- a/api_docs/kbn_inference_integration_flyout.mdx +++ b/api_docs/kbn_inference_integration_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-inference_integration_flyout title: "@kbn/inference_integration_flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/inference_integration_flyout plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/inference_integration_flyout'] --- import kbnInferenceIntegrationFlyoutObj from './kbn_inference_integration_flyout.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index a70f1d03f26a11..91815af1a7baf4 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index e17dbf002a9658..5bd2f82a476b59 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 09c2f90cf9a647..7806977a5ff630 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_ipynb.mdx b/api_docs/kbn_ipynb.mdx index 613484e3bcc1bd..0f55e6da22faa5 100644 --- a/api_docs/kbn_ipynb.mdx +++ b/api_docs/kbn_ipynb.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ipynb title: "@kbn/ipynb" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ipynb plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ipynb'] --- import kbnIpynbObj from './kbn_ipynb.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index c199e942c47367..e2e126ace151e5 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index 2168b894799536..f92880e152af6a 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index 7b38a3b47dbbe1..f7a970eade436d 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index e069b954427bd9..719fe13148e43c 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx index a694f2381cdb4d..edcf7b993d47c0 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index 654988afdd9ad7..b8b7b8305838eb 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_lens_formula_docs.mdx b/api_docs/kbn_lens_formula_docs.mdx index 389fc614a9d046..dcc7887e2c3894 100644 --- a/api_docs/kbn_lens_formula_docs.mdx +++ b/api_docs/kbn_lens_formula_docs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-formula-docs title: "@kbn/lens-formula-docs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-formula-docs plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-formula-docs'] --- import kbnLensFormulaDocsObj from './kbn_lens_formula_docs.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index ac5cc472bd957a..0b3284ccaff5b6 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index a7c06f39b88911..e7296264e4221d 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_content_badge.mdx b/api_docs/kbn_managed_content_badge.mdx index c1e7cc6cb29508..ade696d52c11ec 100644 --- a/api_docs/kbn_managed_content_badge.mdx +++ b/api_docs/kbn_managed_content_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-content-badge title: "@kbn/managed-content-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-content-badge plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-content-badge'] --- import kbnManagedContentBadgeObj from './kbn_managed_content_badge.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index c4805f5d06330f..9ea1627776fddc 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index fa34a83354fba2..e57cd5e7ed8fa3 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index a35cbf8d26019b..bfe63ca555d663 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index be9c1a2e0b319a..679ecc142d4513 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index 35b8de7da86532..5466ac9f128822 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index e32b94df5ef883..389e2027f424a6 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index ecade74c4d9850..ad499b3c90f108 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index 03952391dbad11..2886e76ab11376 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index 9a3bbd297ed9b7..d4d30d03b2e602 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index 8ecac5821b8d7c..d386b31cc29bb0 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index 7f77615f09a8f0..960d7c89e444c8 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index 02190e2aac699e..f846a138ad72d8 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index dac4c65101db2b..cc94cfcc455775 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.devdocs.json b/api_docs/kbn_mapbox_gl.devdocs.json index 89aaae69b68dd8..7f8b965b1d5c22 100644 --- a/api_docs/kbn_mapbox_gl.devdocs.json +++ b/api_docs/kbn_mapbox_gl.devdocs.json @@ -9592,7 +9592,7 @@ "label": "MapEvent", "description": [], "signature": [ - "\"error\" | \"data\" | \"render\" | \"remove\" | \"rotate\" | \"resize\" | \"idle\" | \"zoom\" | \"load\" | \"move\" | \"mousedown\" | \"mouseup\" | \"mouseover\" | \"mousemove\" | \"click\" | \"dblclick\" | \"mouseenter\" | \"mouseleave\" | \"mouseout\" | \"contextmenu\" | \"wheel\" | \"touchstart\" | \"touchend\" | \"touchmove\" | \"touchcancel\" | \"movestart\" | \"moveend\" | \"dragstart\" | \"drag\" | \"dragend\" | \"zoomstart\" | \"zoomend\" | \"rotatestart\" | \"rotateend\" | \"pitchstart\" | \"pitch\" | \"pitchend\" | \"boxzoomstart\" | \"boxzoomend\" | \"boxzoomcancel\" | \"webglcontextlost\" | \"webglcontextrestored\" | \"styledata\" | \"sourcedata\" | \"dataloading\" | \"styledataloading\" | \"sourcedataloading\" | \"styleimagemissing\" | \"style.load\" | \"terrain\" | \"dataabort\" | \"sourcedataabort\"" + "\"error\" | \"data\" | \"move\" | \"render\" | \"remove\" | \"rotate\" | \"resize\" | \"idle\" | \"zoom\" | \"load\" | \"mousedown\" | \"mouseup\" | \"mouseover\" | \"mousemove\" | \"click\" | \"dblclick\" | \"mouseenter\" | \"mouseleave\" | \"mouseout\" | \"contextmenu\" | \"wheel\" | \"touchstart\" | \"touchend\" | \"touchmove\" | \"touchcancel\" | \"movestart\" | \"moveend\" | \"dragstart\" | \"drag\" | \"dragend\" | \"zoomstart\" | \"zoomend\" | \"rotatestart\" | \"rotateend\" | \"pitchstart\" | \"pitch\" | \"pitchend\" | \"boxzoomstart\" | \"boxzoomend\" | \"boxzoomcancel\" | \"webglcontextlost\" | \"webglcontextrestored\" | \"styledata\" | \"sourcedata\" | \"dataloading\" | \"styledataloading\" | \"sourcedataloading\" | \"styleimagemissing\" | \"style.load\" | \"terrain\" | \"dataabort\" | \"sourcedataabort\"" ], "path": "node_modules/maplibre-gl/dist/maplibre-gl.d.ts", "deprecated": false, diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 5d95f72358409a..29fe8a26cc8074 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index be9bcb20e4acae..6b6ab7809564de 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 3a2e1d8eb48553..c682754234786d 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index 3b4dc8c8dbe191..f94006b655dbfa 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_cancellable_search.mdx b/api_docs/kbn_ml_cancellable_search.mdx index 7fda32a6202b64..bd45f8ad1a08b0 100644 --- a/api_docs/kbn_ml_cancellable_search.mdx +++ b/api_docs/kbn_ml_cancellable_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-cancellable-search title: "@kbn/ml-cancellable-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-cancellable-search plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-cancellable-search'] --- import kbnMlCancellableSearchObj from './kbn_ml_cancellable_search.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index bddad4be53cfec..5f6b80c05feb8c 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index 44c318ad0633a7..5869e96f4d4a28 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index 899f0313c8a100..dfdc3b08cbacfc 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index e664eaa61d4240..8a1cd3f0ad4e73 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index cebdf85867838a..c0466967360b11 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index f75310c36f61f9..da283ea5b28482 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index 510e1542d0f119..52e09fb58f7983 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index ec6dec9b9d60c9..7f261994b433ca 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index bd53464f3382e9..f60bb413a2382a 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 3739aefe3f9d3f..80a615093e7f07 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index 040eecbaf53254..d6cb7980ec60d8 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index 63e5c5d6286ec2..f5bce0abc160de 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index 3bb1ec9642670f..2925c0b6db4452 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index 815921c27fdfd1..4bfee361313a4c 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index 8c6dc446dafbde..4b5f183519c842 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index 7733cd5ed15720..f5fb6b5a066d83 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index 008b2619d5bd90..a85bf8421e6c09 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index 9d976957fa6938..ee9cc56bc047a9 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 1b45e8ff581a6f..7100105fa361ad 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_time_buckets.mdx b/api_docs/kbn_ml_time_buckets.mdx index 9bed3e7d98e82d..7a1829d634b788 100644 --- a/api_docs/kbn_ml_time_buckets.mdx +++ b/api_docs/kbn_ml_time_buckets.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-time-buckets title: "@kbn/ml-time-buckets" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-time-buckets plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-time-buckets'] --- import kbnMlTimeBucketsObj from './kbn_ml_time_buckets.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 9f171d79b9144c..34e51866932da0 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_ui_actions.mdx b/api_docs/kbn_ml_ui_actions.mdx index 11c518e24b374f..88be9a72278360 100644 --- a/api_docs/kbn_ml_ui_actions.mdx +++ b/api_docs/kbn_ml_ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-ui-actions title: "@kbn/ml-ui-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-ui-actions plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-ui-actions'] --- import kbnMlUiActionsObj from './kbn_ml_ui_actions.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index d2cda31264ab91..68f724104cb2ce 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_mock_idp_utils.mdx b/api_docs/kbn_mock_idp_utils.mdx index 4a35bdacaf30cb..d56e817f32cfe9 100644 --- a/api_docs/kbn_mock_idp_utils.mdx +++ b/api_docs/kbn_mock_idp_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mock-idp-utils title: "@kbn/mock-idp-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mock-idp-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mock-idp-utils'] --- import kbnMockIdpUtilsObj from './kbn_mock_idp_utils.devdocs.json'; diff --git a/api_docs/kbn_monaco.devdocs.json b/api_docs/kbn_monaco.devdocs.json index e8cc403b3ee300..a432c6389bae22 100644 --- a/api_docs/kbn_monaco.devdocs.json +++ b/api_docs/kbn_monaco.devdocs.json @@ -482,7 +482,7 @@ "label": "getSources", "description": [], "signature": [ - "CallbackFn<{}, { name: string; hidden: boolean; }> | undefined" + "CallbackFn<{}, { name: string; hidden: boolean; title?: string | undefined; dataStreams?: { name: string; title?: string | undefined; }[] | undefined; }> | undefined" ], "path": "packages/kbn-esql-validation-autocomplete/src/shared/types.ts", "deprecated": false, diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 3c3e4138c779fd..23ac7c7f51194f 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index 9992ebe20caaa8..bce22ad4b56e85 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index 1dc5321bcf6971..ab2abedacdfb7d 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index f6153a9f6c1f9c..6f86bf5ff4e022 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx index 7f3e670bbeea49..2cefb2e5feaa8c 100644 --- a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-get-padded-alert-time-range-util title: "@kbn/observability-get-padded-alert-time-range-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-get-padded-alert-time-range-util plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-get-padded-alert-time-range-util'] --- import kbnObservabilityGetPaddedAlertTimeRangeUtilObj from './kbn_observability_get_padded_alert_time_range_util.devdocs.json'; diff --git a/api_docs/kbn_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx index 88d28ea4a83c00..6f7bcb21157f80 100644 --- a/api_docs/kbn_openapi_bundler.mdx +++ b/api_docs/kbn_openapi_bundler.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-bundler title: "@kbn/openapi-bundler" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-bundler plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-bundler'] --- import kbnOpenapiBundlerObj from './kbn_openapi_bundler.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index 418286506e3b36..a3843270d55405 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index c3473550ecdfef..32c15b1d0581ae 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index c57daa10853f1b..0d8c3816185a80 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_osquery_io_ts_types.mdx b/api_docs/kbn_osquery_io_ts_types.mdx index 6e1598dfce37b6..d27bd79efae830 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx index 509330b3de5dc1..998c16ed1affb0 100644 --- a/api_docs/kbn_panel_loader.mdx +++ b/api_docs/kbn_panel_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-panel-loader title: "@kbn/panel-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/panel-loader plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/panel-loader'] --- import kbnPanelLoaderObj from './kbn_panel_loader.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 3033ba99f1bf13..4c5416e26ed0f2 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_check.mdx b/api_docs/kbn_plugin_check.mdx index ea93f44e2c8cf7..b27b01dcff7883 100644 --- a/api_docs/kbn_plugin_check.mdx +++ b/api_docs/kbn_plugin_check.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-check title: "@kbn/plugin-check" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-check plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-check'] --- import kbnPluginCheckObj from './kbn_plugin_check.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 52b89d3991c208..586db8494bb0c2 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index ccfb2e0a5ffe91..6ef469883b64ea 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_presentation_containers.mdx b/api_docs/kbn_presentation_containers.mdx index c5fbf9f7dd1a5a..86b3132502f3c6 100644 --- a/api_docs/kbn_presentation_containers.mdx +++ b/api_docs/kbn_presentation_containers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-containers title: "@kbn/presentation-containers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-containers plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index 57d89d52805003..0e021d0ca307c9 100644 --- a/api_docs/kbn_presentation_publishing.mdx +++ b/api_docs/kbn_presentation_publishing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-publishing title: "@kbn/presentation-publishing" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-publishing plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 98d3a528777500..68813cccd6190a 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 8422a3507cb455..b29ce64a873552 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 939d4a77803906..f4116735259438 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_hooks.mdx b/api_docs/kbn_react_hooks.mdx index b523cd4752ee59..a7443008e41214 100644 --- a/api_docs/kbn_react_hooks.mdx +++ b/api_docs/kbn_react_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-hooks title: "@kbn/react-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-hooks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-hooks'] --- import kbnReactHooksObj from './kbn_react_hooks.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index 3d5d27ff2e549c..0f8bb09a458114 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index f581c1b14ca093..201f21fd2072d5 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index 3b2494976f6aab..23e6f601bf27c8 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index 29999416ca2c6e..98dcc858cab1f3 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index c52481c92a2fad..5f617bee8c48c8 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index a0347314f87514..fb82a4b8975462 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 77e725cfae3fa8..7f7f696d78a68a 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index aa0bd6217293f3..fb5c4a1524b4d9 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index d6a38392579e9e..5a840e912f536e 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index f017da06d9281e..3ff67fc3ea8ce1 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 14bafe45835dc7..89ec0443f6839b 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_csv_share_panel.mdx b/api_docs/kbn_reporting_csv_share_panel.mdx index 037f4030f520af..ce737fb4e4b060 100644 --- a/api_docs/kbn_reporting_csv_share_panel.mdx +++ b/api_docs/kbn_reporting_csv_share_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-csv-share-panel title: "@kbn/reporting-csv-share-panel" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-csv-share-panel plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-csv-share-panel'] --- import kbnReportingCsvSharePanelObj from './kbn_reporting_csv_share_panel.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index 4e6da9fa82d13d..00ce6fed4ce0b5 100644 --- a/api_docs/kbn_reporting_export_types_csv.mdx +++ b/api_docs/kbn_reporting_export_types_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv title: "@kbn/reporting-export-types-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index 954b82beae3f05..03cc56bb5dd51e 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.mdx +++ b/api_docs/kbn_reporting_export_types_csv_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv-common title: "@kbn/reporting-export-types-csv-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index 946ebba102d946..2737f4db07ce45 100644 --- a/api_docs/kbn_reporting_export_types_pdf.mdx +++ b/api_docs/kbn_reporting_export_types_pdf.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf title: "@kbn/reporting-export-types-pdf" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf'] --- import kbnReportingExportTypesPdfObj from './kbn_reporting_export_types_pdf.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf_common.mdx b/api_docs/kbn_reporting_export_types_pdf_common.mdx index bd28fcbcd60fff..574ac8e9ca7345 100644 --- a/api_docs/kbn_reporting_export_types_pdf_common.mdx +++ b/api_docs/kbn_reporting_export_types_pdf_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf-common title: "@kbn/reporting-export-types-pdf-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf-common'] --- import kbnReportingExportTypesPdfCommonObj from './kbn_reporting_export_types_pdf_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png.mdx b/api_docs/kbn_reporting_export_types_png.mdx index 5a3d3485a84a30..2977c93c5c0c41 100644 --- a/api_docs/kbn_reporting_export_types_png.mdx +++ b/api_docs/kbn_reporting_export_types_png.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png title: "@kbn/reporting-export-types-png" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png'] --- import kbnReportingExportTypesPngObj from './kbn_reporting_export_types_png.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png_common.mdx b/api_docs/kbn_reporting_export_types_png_common.mdx index 21a561c316f91c..1fe929de376f33 100644 --- a/api_docs/kbn_reporting_export_types_png_common.mdx +++ b/api_docs/kbn_reporting_export_types_png_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png-common title: "@kbn/reporting-export-types-png-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png-common'] --- import kbnReportingExportTypesPngCommonObj from './kbn_reporting_export_types_png_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_mocks_server.mdx b/api_docs/kbn_reporting_mocks_server.mdx index 502c9b53594fc7..80424616f17b43 100644 --- a/api_docs/kbn_reporting_mocks_server.mdx +++ b/api_docs/kbn_reporting_mocks_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-mocks-server title: "@kbn/reporting-mocks-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-mocks-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index af997976254989..2bdca194559a5d 100644 --- a/api_docs/kbn_reporting_public.mdx +++ b/api_docs/kbn_reporting_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-public title: "@kbn/reporting-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-public plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index 0ed4f1d634e57c..b1e93c3e64713c 100644 --- a/api_docs/kbn_reporting_server.mdx +++ b/api_docs/kbn_reporting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-server title: "@kbn/reporting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index 8f3ff9bd87637e..2cd1f2d49eaff5 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_response_ops_feature_flag_service.mdx b/api_docs/kbn_response_ops_feature_flag_service.mdx index 538573427a564c..832f03fdfeb36c 100644 --- a/api_docs/kbn_response_ops_feature_flag_service.mdx +++ b/api_docs/kbn_response_ops_feature_flag_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-feature-flag-service title: "@kbn/response-ops-feature-flag-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-feature-flag-service plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-feature-flag-service'] --- import kbnResponseOpsFeatureFlagServiceObj from './kbn_response_ops_feature_flag_service.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index abf549f7879dee..02fe8a3f84e658 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_router_to_openapispec.mdx b/api_docs/kbn_router_to_openapispec.mdx index 189a6168162128..3a36a6cad5926a 100644 --- a/api_docs/kbn_router_to_openapispec.mdx +++ b/api_docs/kbn_router_to_openapispec.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-to-openapispec title: "@kbn/router-to-openapispec" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-to-openapispec plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-to-openapispec'] --- import kbnRouterToOpenapispecObj from './kbn_router_to_openapispec.devdocs.json'; diff --git a/api_docs/kbn_router_utils.mdx b/api_docs/kbn_router_utils.mdx index d2bc968cce1129..ff48953d6b839a 100644 --- a/api_docs/kbn_router_utils.mdx +++ b/api_docs/kbn_router_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-utils title: "@kbn/router-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-utils'] --- import kbnRouterUtilsObj from './kbn_router_utils.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index 6753bb86d6d854..2938c97001f605 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 7f70d045f06ee0..bcc4f8825b62b2 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index b68bf847f8b026..3f3dd6ae50a6de 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index 241233903437a6..180f6feaa00b62 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; diff --git a/api_docs/kbn_search_connectors.devdocs.json b/api_docs/kbn_search_connectors.devdocs.json index 2a82021bac368b..3cf388d6f16569 100644 --- a/api_docs/kbn_search_connectors.devdocs.json +++ b/api_docs/kbn_search_connectors.devdocs.json @@ -6499,23 +6499,23 @@ "section": "def-common.ConnectorStatus", "text": "ConnectorStatus" }, - "; description: string | null; language: string | null; configuration: ", + "; description: string | null; language: string | null; pipeline?: ", { "pluginId": "@kbn/search-connectors", "scope": "common", "docId": "kibKbnSearchConnectorsPluginApi", - "section": "def-common.ConnectorConfiguration", - "text": "ConnectorConfiguration" + "section": "def-common.IngestPipelineParams", + "text": "IngestPipelineParams" }, - "; index_name: string | null; pipeline?: ", + " | null | undefined; configuration: ", { "pluginId": "@kbn/search-connectors", "scope": "common", "docId": "kibKbnSearchConnectorsPluginApi", - "section": "def-common.IngestPipelineParams", - "text": "IngestPipelineParams" + "section": "def-common.ConnectorConfiguration", + "text": "ConnectorConfiguration" }, - " | null | undefined; api_key_id: string | null; api_key_secret_id: string | null; custom_scheduling: ", + "; index_name: string | null; api_key_id: string | null; api_key_secret_id: string | null; custom_scheduling: ", { "pluginId": "@kbn/search-connectors", "scope": "common", diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index 61f576ccec4c45..b9c9c36ee0cc4e 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index c04430411fd4ee..95d9c212126d93 100644 --- a/api_docs/kbn_search_errors.mdx +++ b/api_docs/kbn_search_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-errors title: "@kbn/search-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-errors plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-errors'] --- import kbnSearchErrorsObj from './kbn_search_errors.devdocs.json'; diff --git a/api_docs/kbn_search_index_documents.mdx b/api_docs/kbn_search_index_documents.mdx index ee933ffadffc5a..af6487fc4bd749 100644 --- a/api_docs/kbn_search_index_documents.mdx +++ b/api_docs/kbn_search_index_documents.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-index-documents title: "@kbn/search-index-documents" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-index-documents plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-index-documents'] --- import kbnSearchIndexDocumentsObj from './kbn_search_index_documents.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index a4911af523c9fd..164bc07bfde00c 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_search_types.mdx b/api_docs/kbn_search_types.mdx index dacc0a63e4c55f..bde8f9b48769a4 100644 --- a/api_docs/kbn_search_types.mdx +++ b/api_docs/kbn_search_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-types title: "@kbn/search-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_hardening.mdx b/api_docs/kbn_security_hardening.mdx index c1d99a522e9bc9..d77972c92b1695 100644 --- a/api_docs/kbn_security_hardening.mdx +++ b/api_docs/kbn_security_hardening.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-hardening title: "@kbn/security-hardening" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-hardening plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-hardening'] --- import kbnSecurityHardeningObj from './kbn_security_hardening.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx index 78ab45087fb488..6af26b6b71fbf5 100644 --- a/api_docs/kbn_security_plugin_types_common.mdx +++ b/api_docs/kbn_security_plugin_types_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-common title: "@kbn/security-plugin-types-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-common plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-common'] --- import kbnSecurityPluginTypesCommonObj from './kbn_security_plugin_types_common.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_public.mdx b/api_docs/kbn_security_plugin_types_public.mdx index 64ee1ad1bd6457..e9c43ae092a199 100644 --- a/api_docs/kbn_security_plugin_types_public.mdx +++ b/api_docs/kbn_security_plugin_types_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-public title: "@kbn/security-plugin-types-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-public plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index 7476a1f55a9f43..1e2222e5ee35b8 100644 --- a/api_docs/kbn_security_plugin_types_server.mdx +++ b/api_docs/kbn_security_plugin_types_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-server title: "@kbn/security-plugin-types-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-server plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] --- import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index 1ec8908ff8655b..9d91ab74700569 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index f3762cab5063eb..6bf6254bc2591c 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index 63f4a70fb155c4..d0117600479947 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-side-nav'] --- import kbnSecuritySolutionSideNavObj from './kbn_security_solution_side_nav.devdocs.json'; diff --git a/api_docs/kbn_security_solution_storybook_config.mdx b/api_docs/kbn_security_solution_storybook_config.mdx index 1d7460b5e9c071..168d289b799cd8 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 337f9ac61e761b..2ac141175ccf8a 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index 7737f3b2578f9a..d6a36964377442 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index 0e9c907dcd407c..8762cacb033b33 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 787dc2539f43f4..ff2f0609cc7408 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index 8693ad038c7fde..09104e8d6febc8 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index da917f28d8f8fa..873699f6b40923 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index a72ea475312b40..68eaaad8c99b10 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 07d7b4f7cc05b1..c78391812aced7 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 843e91cd417389..fdabec7085bb6e 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index af215ed77ffa20..dd230ff4e75d23 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 57d831ae429c54..69cb2d0521c298 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index 63316808fdde3c..6b3e626eccecf0 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index 28a03759317715..a2a939321dd147 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index d5b841b270615a..11a08c128e4f57 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index f444befb87ea9c..ef5bf78923fbd2 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index 825c6d54bda3cf..21bee7c0e72a24 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 59e218ff76cb34..dc2b54cb365bd5 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index aa80f0b9ec5734..1f2f176f841e3f 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 811665eb47b51d..7bf9a997101b8c 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index c60933aa55a3b8..ca8a403348209a 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index 79fd5ca3170ce7..16ca494177e310 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index 3786cf44243be6..e52d006de02334 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index f98f68069a3d11..d5b634131da1a2 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 9fa1a0a96fc5eb..3caf5ac24cec27 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index 86bb254e27ceef..08bc40afae32cb 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index d055e16990504a..9745ecdb8186c5 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index f9430a3121623d..404f8742996602 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 479d22cd7919b1..9333d04496cb47 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index f2f59187e78bd2..ef29350965f530 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index f7bcd8a674ca24..d3673b25f72e76 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index c8f79c0b8358e6..5cb78c021e1f9c 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index a3f3cb94eb74ed..0a2ead2d378895 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index 6927e6aef13c55..239d1b323afe63 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index b638794940fb2c..b8ece7498308d5 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index fe51f1707507a1..d66a1c29d299b1 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index 282088305558bc..4af0208d8e674f 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index 16d456a7c75b4a..da0e05f1c19c19 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index b431671ab16b3e..2f8bbde5a2807c 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index 6c1c20a32139f0..3bd1daa4136c0f 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index 5b8d449359e9bc..259a2ef67160ad 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index f45045dcaffab9..fbd2ad9877dfa5 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index 1f2e3ff7d743a8..b43f928c2921b8 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index ce75751d7cb980..29a5b2b890b555 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index c35451215f2303..70cd3f8c5a62ec 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index cf0a2a23e81ec4..e92d85b21dea6b 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 7d7ecdc6922e87..279b0490c5cbad 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index f772e6004e16d2..17edc6261ff590 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index 5be2c91a22b83c..073fc1ac1af796 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index 887a31b40b2808..17fcd1e4f0c907 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index 7511487ba56bf7..fe6a0f30a222d8 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index 88c3b4d5eb75f6..1657db0e5712dc 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index 0ce60fec248f9c..faa0052cdefe55 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index 831e5bdba86525..095b8d4616d752 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index 7740c3e4c160c2..bff0a5c9cfbcde 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index 13423d36e33c65..bf07f8e2bbba62 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index be82ba5e352dd4..adf63c4ec483ba 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index a7bb6856b2dc55..5287ba423855e6 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 6fc5f819983cf3..33ab370ae2fac2 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index e53ad09f41e055..4029b95750832b 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 6144fc2b154d37..92f3ebba2f5dfa 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index 638e6c72f0cea3..12cbb0872b2e1a 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index 69068b73c4fb5a..d39b8ab858fc29 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index d2ece90392a850..b82e7bc78626ab 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_tabbed_modal.mdx b/api_docs/kbn_shared_ux_tabbed_modal.mdx index 7d52676fbebc4c..261247fd4298c7 100644 --- a/api_docs/kbn_shared_ux_tabbed_modal.mdx +++ b/api_docs/kbn_shared_ux_tabbed_modal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-tabbed-modal title: "@kbn/shared-ux-tabbed-modal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-tabbed-modal plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-tabbed-modal'] --- import kbnSharedUxTabbedModalObj from './kbn_shared_ux_tabbed_modal.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 23ce9cf96a2a8a..1a435031fb47be 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 3a7ba2b4f2f63e..aa10690cafe769 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 14d5c70653e932..9748374475f976 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_predicates.mdx b/api_docs/kbn_sort_predicates.mdx index 2011280cc05057..8f8c28195b779a 100644 --- a/api_docs/kbn_sort_predicates.mdx +++ b/api_docs/kbn_sort_predicates.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-predicates title: "@kbn/sort-predicates" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-predicates plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-predicates'] --- import kbnSortPredicatesObj from './kbn_sort_predicates.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 3cdbb6cb2c6598..c6eab71a6e0c67 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index 9252cdc7046f5d..0112000b7a26c4 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index cd1c35ec26988f..943833768aeacf 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index d3d28173929727..0d9fa30a0949c7 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 4421b403401223..64f82b945cbc0d 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index 1788f6e0829da1..29b758c4be49cf 100644 --- a/api_docs/kbn_test_eui_helpers.mdx +++ b/api_docs/kbn_test_eui_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-eui-helpers title: "@kbn/test-eui-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-eui-helpers plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-eui-helpers'] --- import kbnTestEuiHelpersObj from './kbn_test_eui_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 16fb734220c896..468d56ee570b16 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 38d549f82a90dd..0e0df8e1fee93f 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_text_based_editor.mdx b/api_docs/kbn_text_based_editor.mdx index 75e745709a74f4..a274863d31ad66 100644 --- a/api_docs/kbn_text_based_editor.mdx +++ b/api_docs/kbn_text_based_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-text-based-editor title: "@kbn/text-based-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/text-based-editor plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/text-based-editor'] --- import kbnTextBasedEditorObj from './kbn_text_based_editor.devdocs.json'; diff --git a/api_docs/kbn_timerange.mdx b/api_docs/kbn_timerange.mdx index 2d097d5e75e74d..d3e5ad7feb050d 100644 --- a/api_docs/kbn_timerange.mdx +++ b/api_docs/kbn_timerange.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-timerange title: "@kbn/timerange" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/timerange plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/timerange'] --- import kbnTimerangeObj from './kbn_timerange.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 9e716aecc945cf..8312393b8890a0 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index 5bdef7f4e25c69..b8ef08f8eec8f3 100644 --- a/api_docs/kbn_triggers_actions_ui_types.mdx +++ b/api_docs/kbn_triggers_actions_ui_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-triggers-actions-ui-types title: "@kbn/triggers-actions-ui-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/triggers-actions-ui-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; diff --git a/api_docs/kbn_try_in_console.mdx b/api_docs/kbn_try_in_console.mdx index 3c3e9e346edad2..94ddd39fdd6451 100644 --- a/api_docs/kbn_try_in_console.mdx +++ b/api_docs/kbn_try_in_console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-try-in-console title: "@kbn/try-in-console" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/try-in-console plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/try-in-console'] --- import kbnTryInConsoleObj from './kbn_try_in_console.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index db8ccb63f12c8e..b13e774e8dd1d3 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 8428e9a42bbd7d..83d4f24f659892 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index 4acf3eb5e68ba5..cf0d74cfcf5d60 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.devdocs.json b/api_docs/kbn_ui_shared_deps_src.devdocs.json index e74492ad289254..5a4f7663f18a04 100644 --- a/api_docs/kbn_ui_shared_deps_src.devdocs.json +++ b/api_docs/kbn_ui_shared_deps_src.devdocs.json @@ -443,17 +443,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "@kbn/ui-shared-deps-src", - "id": "def-common.externals.elasticeuidisteui_charts_theme", - "type": "string", - "tags": [], - "label": "'@elastic/eui/dist/eui_charts_theme'", - "description": [], - "path": "packages/kbn-ui-shared-deps-src/src/definitions.js", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "@kbn/ui-shared-deps-src", "id": "def-common.externals.hellopangeadnd", diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index 45443736b64cf4..3e366650b981a3 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 56 | 0 | 47 | 0 | +| 55 | 0 | 46 | 0 | ## Common diff --git a/api_docs/kbn_ui_theme.devdocs.json b/api_docs/kbn_ui_theme.devdocs.json index 94f3bf511028b2..f7b49a9d755a3a 100644 --- a/api_docs/kbn_ui_theme.devdocs.json +++ b/api_docs/kbn_ui_theme.devdocs.json @@ -69,18 +69,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "@kbn/monaco", - "path": "packages/kbn-monaco/src/esql/lib/esql_theme.ts" - }, - { - "plugin": "@kbn/monaco", - "path": "packages/kbn-monaco/src/esql/lib/esql_theme.ts" - }, - { - "plugin": "@kbn/monaco", - "path": "packages/kbn-monaco/src/esql/lib/esql_theme.ts" - }, { "plugin": "@kbn/monaco", "path": "packages/kbn-monaco/src/esql/lib/esql_theme.ts" diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 11c3a781902145..a316100c89324a 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index 6470406f9b3cbf..ebaebbf0d1c19e 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index 0e904c901ade3e..9016bea59786ac 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 0b3533175afd74..d7b8892935c743 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index 3529addc442684..13d0692fda595f 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_prompt.mdx b/api_docs/kbn_unsaved_changes_prompt.mdx index 6877c9595ecd24..28de503ac92cff 100644 --- a/api_docs/kbn_unsaved_changes_prompt.mdx +++ b/api_docs/kbn_unsaved_changes_prompt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-prompt title: "@kbn/unsaved-changes-prompt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-prompt plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-prompt'] --- import kbnUnsavedChangesPromptObj from './kbn_unsaved_changes_prompt.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 7aa3a96e564519..0e01d98f675325 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 5149cf98e47f94..0eca3620287960 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index 5fe09a5bb7435d..51d6e23f8b8028 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index d02ac34ef384fe..857110d8f912fc 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index 3ad836e69f7ad8..3de74eb88c3abc 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 7a12739a8a49bd..fff13aac1b112e 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_visualization_utils.mdx b/api_docs/kbn_visualization_utils.mdx index 7adc25184d8ebd..94cabdfae49a63 100644 --- a/api_docs/kbn_visualization_utils.mdx +++ b/api_docs/kbn_visualization_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-utils title: "@kbn/visualization-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-utils'] --- import kbnVisualizationUtilsObj from './kbn_visualization_utils.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index 76384b88894adc..a093809f851a79 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 3912fb378253cd..78c6e883b6e67a 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.devdocs.json b/api_docs/kbn_zod_helpers.devdocs.json index 2001282ced3945..3ea762172aa254 100644 --- a/api_docs/kbn_zod_helpers.devdocs.json +++ b/api_docs/kbn_zod_helpers.devdocs.json @@ -58,6 +58,49 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.buildRouteValidationWithZod", + "type": "Function", + "tags": [], + "label": "buildRouteValidationWithZod", + "description": [ + "\nZod validation factory for Kibana route's request validation.\nIt allows to pass a Zod schema for parameters, query and/or body validation.\n\nExample:\n\n```ts\nrouter.versioned\n .post({\n access: 'public',\n path: MY_URL,\n })\n .addVersion(\n {\n version: 'my-version',\n validate: {\n request: {\n params: buildRouteValidationWithZod(MyRequestParamsZodSchema),\n query: buildRouteValidationWithZod(MyRequestQueryZodSchema),\n body: buildRouteValidationWithZod(MyRequestBodyZodSchema),\n },\n },\n },\n```" + ], + "signature": [ + "(schema: ZodSchema) => ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.RouteValidationFunction", + "text": "RouteValidationFunction" + }, + "" + ], + "path": "packages/kbn-zod-helpers/src/build_route_validation_with_zod.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.buildRouteValidationWithZod.$1", + "type": "Uncategorized", + "tags": [], + "label": "schema", + "description": [], + "signature": [ + "ZodSchema" + ], + "path": "packages/kbn-zod-helpers/src/build_route_validation_with_zod.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/zod-helpers", "id": "def-common.expectParseError", diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index 21ca40473b28ef..8c5ae93d1de778 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-detection-rule-management](https://github.com/orgs/el | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 18 | 0 | 9 | 0 | +| 20 | 0 | 10 | 0 | ## Common diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 68e7dc00956854..2578cad63ef056 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index a771d0a42ff2f3..7eaac80a171b14 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index a7ed980f094eb0..350d92ac57c194 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 307f3dc924d143..97af756fbcb2a9 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 8d5aa484a4f291..1aacddd53ae9cb 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index 91f753208affbf..52990b67a88050 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 3553269ec96e9b..53e6a7de6aaf9d 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 05a287f91b1295..7ff63218c70ce0 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index 5dbd8b3e558aa7..bb6e28921dcea3 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index ab66bbd113633c..d1dbb67ba6ccbc 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/logs_data_access.mdx b/api_docs/logs_data_access.mdx index 6f9539d43aac26..8e77013849428b 100644 --- a/api_docs/logs_data_access.mdx +++ b/api_docs/logs_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsDataAccess title: "logsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the logsDataAccess plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsDataAccess'] --- import logsDataAccessObj from './logs_data_access.devdocs.json'; diff --git a/api_docs/logs_explorer.mdx b/api_docs/logs_explorer.mdx index 80e08ec4cf6f70..f853c879c5cc25 100644 --- a/api_docs/logs_explorer.mdx +++ b/api_docs/logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsExplorer title: "logsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logsExplorer plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsExplorer'] --- import logsExplorerObj from './logs_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 3f2e723b5579a5..b3b4149db03f56 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index ed2c0c3d95e7bf..128a57183b2079 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index d6f7a1d8cce9a6..ada73ac30ea8f5 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 11fbb4d97f7e7f..dcf3eed8d65e7c 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index c1e9164d209219..7621ac99fed0d3 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 3d83b78e1cf32a..242a6df0278507 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index 0d1627d4941c81..a54ec10197db9a 100644 --- a/api_docs/mock_idp_plugin.mdx +++ b/api_docs/mock_idp_plugin.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mockIdpPlugin title: "mockIdpPlugin" image: https://source.unsplash.com/400x175/?github description: API docs for the mockIdpPlugin plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] --- import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 06c2e7e11e522d..f00d547d595b28 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 3f382a0a6f1a3a..37bdf4ef856ead 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 4fc030a3e77126..36019f225e1c47 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index 056c9b626c0ac2..ed3a9bbce6fecf 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index 68e23117c862a4..2ac60ca6d01aaa 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index acdbb39c7900e7..fefcc8e26a90f0 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index 278f66f3723ec5..ed3e91babeb4fe 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -155,7 +155,7 @@ "label": "AlertSummary", "description": [], "signature": [ - "({ alertSummaryFields }: AlertSummaryProps) => JSX.Element" + "({ alert, alertSummaryFields }: AlertSummaryProps) => JSX.Element" ], "path": "x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_summary.tsx", "deprecated": false, @@ -166,7 +166,7 @@ "id": "def-public.AlertSummary.$1", "type": "Object", "tags": [], - "label": "{ alertSummaryFields }", + "label": "{ alert, alertSummaryFields }", "description": [], "signature": [ "AlertSummaryProps" diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index eb76936ebe69db..8b0145aebed4c3 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index 62922ef331bbf6..944c331bf49d7d 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index 2d72d3c5759265..3d3c4c26a72b59 100644 --- a/api_docs/observability_a_i_assistant_app.mdx +++ b/api_docs/observability_a_i_assistant_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistantApp title: "observabilityAIAssistantApp" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistantApp plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistantApp'] --- import observabilityAIAssistantAppObj from './observability_a_i_assistant_app.devdocs.json'; diff --git a/api_docs/observability_ai_assistant_management.mdx b/api_docs/observability_ai_assistant_management.mdx index 368830b966205e..0a6cd4f656e10e 100644 --- a/api_docs/observability_ai_assistant_management.mdx +++ b/api_docs/observability_ai_assistant_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAiAssistantManagement title: "observabilityAiAssistantManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAiAssistantManagement plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAiAssistantManagement'] --- import observabilityAiAssistantManagementObj from './observability_ai_assistant_management.devdocs.json'; diff --git a/api_docs/observability_logs_explorer.mdx b/api_docs/observability_logs_explorer.mdx index 509dc56ef16b80..3106ad25e10ba2 100644 --- a/api_docs/observability_logs_explorer.mdx +++ b/api_docs/observability_logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogsExplorer title: "observabilityLogsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogsExplorer plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogsExplorer'] --- import observabilityLogsExplorerObj from './observability_logs_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 47b27382ed39fb..9c73c46efa49f3 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 9a7f818c21a99f..f5e26915cb9b42 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 2656666b957d77..ac6690ba3a9dda 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index 31904a5a9443e7..4324d1d11c14ab 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 13c56f83dab908..80b6b3136a7d91 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,13 +15,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 806 | 692 | 42 | +| 805 | 689 | 42 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 49119 | 239 | 37584 | 1875 | +| 49310 | 238 | 37600 | 1879 | ## Plugin Directory @@ -57,7 +57,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 271 | 0 | 252 | 1 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 129 | 0 | 123 | 12 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 54 | 0 | 51 | 0 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | 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. | 3194 | 31 | 2585 | 24 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | 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. | 3199 | 31 | 2590 | 24 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 8 | 0 | 8 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 35 | 0 | 25 | 5 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Reusable data view field editor across Kibana | 72 | 0 | 33 | 0 | @@ -101,7 +101,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | 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. | 84 | 0 | 84 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 240 | 0 | 24 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Simple UI for managing files in Kibana | 2 | 0 | 2 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1338 | 5 | 1216 | 72 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1339 | 5 | 1217 | 72 | | ftrApis | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 72 | 0 | 14 | 5 | | globalSearchBar | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | @@ -117,7 +117,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | | inputControlVis | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Input Control visualization to Kibana | 0 | 0 | 0 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 127 | 2 | 100 | 4 | -| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | A simple example of how to use core's routing services test | 69 | 0 | 69 | 0 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | A simple example of how to use core's routing services test | 38 | 0 | 33 | 1 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides UI and APIs for the interactive setup mode. | 28 | 0 | 18 | 0 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 95 | 0 | 95 | 4 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 6 | 0 | 6 | 0 | @@ -247,12 +247,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 33 | 0 | 33 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 237 | 0 | 223 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 73 | 0 | 73 | 2 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 98 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 0 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 19 | 0 | 0 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 23 | 0 | 0 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 19 | 0 | 0 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 22 | 0 | 1 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 18 | 0 | 18 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 4 | 0 | 4 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 49 | 0 | 49 | 8 | @@ -276,17 +271,18 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 217 | 0 | 180 | 9 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 79 | 0 | 50 | 9 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 24 | 0 | 24 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 144 | 3 | 141 | 20 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 146 | 2 | 142 | 20 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 10 | 0 | 8 | 4 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 8 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 8 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 10 | 0 | 10 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 48 | 0 | 32 | 3 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 30 | 0 | 30 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 195 | 1 | 128 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 0 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 101 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 7 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 3 | 0 | 0 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 100 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 5 | 0 | 5 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 103 | 0 | 27 | 0 | @@ -352,7 +348,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 54 | 7 | 54 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 13 | 0 | 13 | 1 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 488 | 2 | 193 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 489 | 2 | 193 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 92 | 0 | 79 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 44 | 0 | 43 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 2 | 0 | @@ -463,7 +459,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 51 | 0 | 51 | 1 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 14 | 0 | 9 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 80 | 0 | 80 | 1 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 1 | 0 | 0 | 0 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 5 | 0 | 4 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 44 | 0 | 43 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 5 | 0 | 5 | 0 | @@ -482,15 +478,16 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 102 | 0 | 86 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 15 | 0 | 9 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 38 | 2 | 33 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 114 | 0 | 88 | 0 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 120 | 0 | 94 | 1 | | | [@elastic/docs](https://github.com/orgs/elastic/teams/docs) | - | 77 | 0 | 77 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 5 | 0 | 5 | 1 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 41 | 0 | 27 | 6 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 152 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 33 | 0 | 24 | 1 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 13 | 0 | 5 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 35 | 0 | 34 | 0 | | | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 165 | 0 | 138 | 9 | -| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 295 | 0 | 276 | 0 | +| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 305 | 0 | 286 | 0 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 20 | 0 | 20 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 52 | 0 | 37 | 7 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 32 | 0 | 19 | 1 | @@ -498,9 +495,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 269 | 1 | 209 | 15 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 26 | 0 | 26 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 68 | 1 | 68 | 7 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 68 | 1 | 68 | 9 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 53 | 0 | 51 | 0 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 194 | 0 | 184 | 10 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 189 | 0 | 178 | 10 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 39 | 0 | 39 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 0 | 52 | 1 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 39 | 0 | 14 | 1 | @@ -729,7 +726,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 39 | 0 | 25 | 1 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 86 | 0 | 86 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 42 | 0 | 28 | 0 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 56 | 0 | 47 | 0 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 55 | 0 | 46 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 9 | 0 | 8 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 153 | 0 | 81 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 18 | 0 | 17 | 5 | @@ -745,5 +742,5 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 10 | 0 | 9 | 1 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 13 | 0 | 13 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 6 | 0 | 2 | 0 | -| | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 18 | 0 | 9 | 0 | +| | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 20 | 0 | 10 | 0 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index 55e27dddad02f8..4df0ee0b57d978 100644 --- a/api_docs/presentation_panel.mdx +++ b/api_docs/presentation_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationPanel title: "presentationPanel" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationPanel plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationPanel'] --- import presentationPanelObj from './presentation_panel.devdocs.json'; diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 0cbb54c1599bc3..7e59e1b4283059 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 59843ba7bdd49c..b03bdffd3b0d2f 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index 5c2ba575a0824f..e3310f1e571a07 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 5dd63fc0897b04..1b78a818df00f2 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index 006a1a383fb191..10d2a95a204f36 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index e82d752c9c7135..3c7589a1dfaa44 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 982b4f418e67b9..f39c370de06fc1 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index cacdcf0747d1fe..a046e09ac1206d 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 5fb36ebc0642e1..2b3aebccf8f440 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index df8d813489241b..dfcabf012f816b 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 71d04fa6f6d061..a4b75fa8bf8afa 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index 0f855887386a8d..997699a68579a8 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index 0e2007a50b8711..a353a4cff8bc99 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/saved_search.mdx b/api_docs/saved_search.mdx index c65779a953eb0e..5fe795374d9fdc 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedSearch'] --- import savedSearchObj from './saved_search.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 6061c6ce60372f..8b0e1bbb438382 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index 41de4c90572e6b..f8503be8f380b1 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/search_connectors.mdx b/api_docs/search_connectors.mdx index e27f2058a1a4db..45a03aa097976c 100644 --- a/api_docs/search_connectors.mdx +++ b/api_docs/search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchConnectors title: "searchConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the searchConnectors plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './search_connectors.devdocs.json'; diff --git a/api_docs/search_inference_endpoints.mdx b/api_docs/search_inference_endpoints.mdx index 7c617046a080e6..960e4e7e489605 100644 --- a/api_docs/search_inference_endpoints.mdx +++ b/api_docs/search_inference_endpoints.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchInferenceEndpoints title: "searchInferenceEndpoints" image: https://source.unsplash.com/400x175/?github description: API docs for the searchInferenceEndpoints plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchInferenceEndpoints'] --- import searchInferenceEndpointsObj from './search_inference_endpoints.devdocs.json'; diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index efc97cf266849c..470c28d2868b4a 100644 --- a/api_docs/search_notebooks.mdx +++ b/api_docs/search_notebooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchNotebooks title: "searchNotebooks" image: https://source.unsplash.com/400x175/?github description: API docs for the searchNotebooks plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNotebooks'] --- import searchNotebooksObj from './search_notebooks.devdocs.json'; diff --git a/api_docs/search_playground.mdx b/api_docs/search_playground.mdx index fd6257e783ef79..1f957baa893ee2 100644 --- a/api_docs/search_playground.mdx +++ b/api_docs/search_playground.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchPlayground title: "searchPlayground" image: https://source.unsplash.com/400x175/?github description: API docs for the searchPlayground plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index d1327bb9f85f58..ad7fdca6c19f6b 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index 36c431192543d8..659f8ee5875278 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -485,7 +485,7 @@ "\nExperimental flag needed to enable the link" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"agentStatusClientEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutDisabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineEnabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"perFieldPrebuiltRulesDiffingEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"aiAssistantFlyoutMode\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"agentStatusClientEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutDisabled\" | \"notesEnabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineEnabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"perFieldPrebuiltRulesDiffingEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"aiAssistantFlyoutMode\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -565,7 +565,7 @@ "\nExperimental flag needed to disable the link. Opposite of experimentalKey" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"agentStatusClientEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutDisabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineEnabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"perFieldPrebuiltRulesDiffingEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"aiAssistantFlyoutMode\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"agentStatusClientEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutDisabled\" | \"notesEnabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineEnabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"perFieldPrebuiltRulesDiffingEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"aiAssistantFlyoutMode\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -1964,7 +1964,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutDisabled: boolean; readonly notesEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -3071,7 +3071,7 @@ "\nThe security solution generic experimental features" ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutDisabled: boolean; readonly notesEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", "deprecated": false, @@ -3247,7 +3247,7 @@ "label": "ExperimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutDisabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutDisabled: boolean; readonly notesEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3313,7 +3313,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionsEnabled: true; readonly endpointResponseActionsEnabled: true; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: false; readonly agentStatusClientEnabled: false; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: false; readonly responseActionScanEnabled: false; readonly alertsPageChartsEnabled: true; readonly alertTypeEnabled: false; readonly expandableFlyoutDisabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly alertSuppressionForEsqlRuleEnabled: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: false; readonly jamfDataInAnalyzerEnabled: false; readonly jsonPrebuiltRulesDiffingEnabled: true; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineEnabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly perFieldPrebuiltRulesDiffingEnabled: true; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: false; readonly aiAssistantFlyoutMode: true; readonly valueListItemsModalEnabled: true; readonly bulkCustomHighlightedFieldsEnabled: false; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: false; }" + "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionsEnabled: true; readonly endpointResponseActionsEnabled: true; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: false; readonly agentStatusClientEnabled: false; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: false; readonly responseActionScanEnabled: false; readonly alertsPageChartsEnabled: true; readonly alertTypeEnabled: false; readonly expandableFlyoutDisabled: false; readonly notesEnabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly alertSuppressionForEsqlRuleEnabled: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: false; readonly jamfDataInAnalyzerEnabled: false; readonly jsonPrebuiltRulesDiffingEnabled: true; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineEnabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly perFieldPrebuiltRulesDiffingEnabled: true; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: false; readonly aiAssistantFlyoutMode: true; readonly valueListItemsModalEnabled: true; readonly bulkCustomHighlightedFieldsEnabled: false; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: false; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 09fd66a8fa53ba..10fb34dfcd75ab 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index da3e0b614f45bb..c96d7a20b5e9ff 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index 4dfe48856ba188..7acea530f5fc5b 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index 2b167cbb92301d..1eb61bcf6de728 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index 0a361ed9f29d42..c403796a2f2804 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index e48d941822de49..c882d39ee8c64f 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index dc8c512217b739..39e2308ac3b35f 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index 65f4bf5340d47d..0955b3e6997b22 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index 4615111556016b..8bb7ffb38c2ea4 100644 --- a/api_docs/slo.mdx +++ b/api_docs/slo.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/slo title: "slo" image: https://source.unsplash.com/400x175/?github description: API docs for the slo plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'slo'] --- import sloObj from './slo.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 895059ad9b0556..359079def7dbc1 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.devdocs.json b/api_docs/spaces.devdocs.json index 0d6cb86b49fa46..b19ac583710161 100644 --- a/api_docs/spaces.devdocs.json +++ b/api_docs/spaces.devdocs.json @@ -1793,7 +1793,14 @@ "\nSolution selected for this space." ], "signature": [ - "\"search\" | \"security\" | \"observability\" | \"classic\" | undefined" + { + "pluginId": "cloud", + "scope": "common", + "docId": "kibCloudPluginApi", + "section": "def-common.OnBoardingDefaultSolution", + "text": "OnBoardingDefaultSolution" + }, + " | \"classic\" | undefined" ], "path": "x-pack/plugins/spaces/common/types/space/v1.ts", "deprecated": false, @@ -1825,7 +1832,15 @@ "The space to represent with an avatar." ], "signature": [ - "{ id?: string | undefined; name?: string | undefined; description?: string | undefined; color?: string | undefined; initials?: string | undefined; imageUrl?: string | undefined; disabledFeatures?: string[] | undefined; _reserved?: boolean | undefined; solution?: \"search\" | \"security\" | \"observability\" | \"classic\" | undefined; }" + "{ id?: string | undefined; name?: string | undefined; description?: string | undefined; color?: string | undefined; initials?: string | undefined; imageUrl?: string | undefined; disabledFeatures?: string[] | undefined; _reserved?: boolean | undefined; solution?: ", + { + "pluginId": "cloud", + "scope": "common", + "docId": "kibCloudPluginApi", + "section": "def-common.OnBoardingDefaultSolution", + "text": "OnBoardingDefaultSolution" + }, + " | \"classic\" | undefined; }" ], "path": "x-pack/plugins/spaces/public/space_avatar/types.ts", "deprecated": false, @@ -3701,7 +3716,14 @@ "\nSolution selected for this space." ], "signature": [ - "\"search\" | \"security\" | \"observability\" | \"classic\" | undefined" + { + "pluginId": "cloud", + "scope": "common", + "docId": "kibCloudPluginApi", + "section": "def-common.OnBoardingDefaultSolution", + "text": "OnBoardingDefaultSolution" + }, + " | \"classic\" | undefined" ], "path": "x-pack/plugins/spaces/common/types/space/v1.ts", "deprecated": false, @@ -4951,7 +4973,14 @@ "\nSolution selected for this space." ], "signature": [ - "\"search\" | \"security\" | \"observability\" | \"classic\" | undefined" + { + "pluginId": "cloud", + "scope": "common", + "docId": "kibCloudPluginApi", + "section": "def-common.OnBoardingDefaultSolution", + "text": "OnBoardingDefaultSolution" + }, + " | \"classic\" | undefined" ], "path": "x-pack/plugins/spaces/common/types/space/v1.ts", "deprecated": false, diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index e9f21582eff651..385368b87f6546 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 3737d2302fe6b0..3314b5bb8aa633 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/stack_connectors.devdocs.json b/api_docs/stack_connectors.devdocs.json index 435af06ccdd6b8..447872c4249edb 100644 --- a/api_docs/stack_connectors.devdocs.json +++ b/api_docs/stack_connectors.devdocs.json @@ -186,7 +186,7 @@ }, "; }>" ], - "path": "x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts", + "path": "x-pack/plugins/stack_connectors/server/connector_types/webhook/schema.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/stack_connectors.mdx b/api_docs/stack_connectors.mdx index 6b67580e44db90..086640353d71c7 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index f49b7846ed0955..03645e34e324d5 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 178ea146c56bad..2c751b121ed499 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 2a237ce79ed098..51d70a87ff4b49 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index c35b4097e77e89..176820c472d6fc 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 444de09aa6b4ad..ce2e6eb5c50d83 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/text_based_languages.mdx b/api_docs/text_based_languages.mdx index 2b06f627d6f2de..7426e2bcc3ed33 100644 --- a/api_docs/text_based_languages.mdx +++ b/api_docs/text_based_languages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/textBasedLanguages title: "textBasedLanguages" image: https://source.unsplash.com/400x175/?github description: API docs for the textBasedLanguages plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'textBasedLanguages'] --- import textBasedLanguagesObj from './text_based_languages.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 5b74a013694046..5e6c067200b756 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index bcb9dba7866d9a..0fbca32935a9a0 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 76563f3a7636ac..c283e9cbb19400 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index a82268cb54719c..947d503130b720 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index dc674fa70fdf79..9927f905c32321 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 953b01ceadd394..f0c965a6d86fde 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index d738743a9477ec..797100653e885f 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 2454d26694b22b..673a04e07caa21 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.devdocs.json b/api_docs/unified_search.devdocs.json index 3a6a417a835bd7..9a084801174c43 100644 --- a/api_docs/unified_search.devdocs.json +++ b/api_docs/unified_search.devdocs.json @@ -1593,9 +1593,9 @@ "signature": [ "{ optIn: (optInConfig: ", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.OptInConfig", "text": "OptInConfig" }, @@ -1603,9 +1603,9 @@ "Observable", "<", { - "pluginId": "@kbn/analytics-client", + "pluginId": "@kbn/ebt", "scope": "common", - "docId": "kibKbnAnalyticsClientPluginApi", + "docId": "kibKbnEbtPluginApi", "section": "def-common.TelemetryCounter", "text": "TelemetryCounter" }, diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 6ddb906f1436ad..da150ddd187d51 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 7d9046ef2e02b5..3828629b7de403 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index 35f9262187c034..8b9feb48b2554a 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index d15b383e344daa..64a832b6cff6c9 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.devdocs.json b/api_docs/usage_collection.devdocs.json index b573f8c8d3d7e5..609cbc0a5a6334 100644 --- a/api_docs/usage_collection.devdocs.json +++ b/api_docs/usage_collection.devdocs.json @@ -1869,7 +1869,7 @@ "signature": [ "\"boolean\" | \"keyword\" | \"text\" | \"date\" | \"integer\" | \"long\" | \"short\" | \"byte\" | \"float\" | \"double\"" ], - "path": "packages/analytics/client/src/schema/types.ts", + "path": "packages/analytics/ebt/client/src/schema/types.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 8d1371644bd4dc..436db094913ba4 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index aa257292348cd4..6101ac7d027d24 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index 4c024378c51a52..890eb0c990a2e5 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 984c1023796042..6aff52a01cd88e 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index de21d886b7c467..dca9fa99c07b0a 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index ee4144f629efe5..6f52c4d6726a1b 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index 0cd01627505778..c984f1e20a8318 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 59414d94e8ed86..3dce4637737aea 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index d9f9590acbe695..1106d22596c133 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index 30af10196561f4..d899070ea869fd 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index 5c5f8367dc6b9c..89682e5f505283 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index 0ca9f2fe7118c1..4ae390b8e9a7c6 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 1176ba240c38e5..862c90efea645b 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2024-06-18 +date: 2024-06-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From dbdc797781273eb9387744b5b9da3dfc7b6e8a5c Mon Sep 17 00:00:00 2001 From: Gerard Soldevila Date: Wed, 19 Jun 2024 10:15:05 +0200 Subject: [PATCH 077/123] Prevent write blocking target index during reindex migration (#185939) ## Summary Addresses https://github.com/elastic/kibana/issues/185918 The idea is to simply check whether the index that a migrator is trying to `write_block` (aka the source of the reindex operation) matches the target index name. In this case: * We assume that other migrators are half way through, ahead of us. * We abort operation and trust other instances' migrators to finish the job. * Subsequent restart, when migration has finished, should basically be a no-op. --- .../src/actions/clone_index.ts | 2 +- .../src/actions/create_index.ts | 2 +- .../src/actions/index.ts | 9 ++++ .../src/actions/initialize_action.ts | 2 +- .../src/actions/safe_write_block.test.ts | 54 +++++++++++++++++++ .../src/actions/safe_write_block.ts | 47 ++++++++++++++++ .../src/actions/update_and_pickup_mappings.ts | 2 +- .../update_source_mappings_properties.ts | 2 +- .../src/model/model.test.ts | 9 ++++ .../src/model/model.ts | 8 +++ .../src/next.ts | 6 ++- 11 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/safe_write_block.test.ts create mode 100644 packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/safe_write_block.ts diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/clone_index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/clone_index.ts index 7334f17191df0c..2271a2773cfaba 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/clone_index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/clone_index.ts @@ -8,7 +8,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; -import { pipe } from 'fp-ts/lib/pipeable'; +import { pipe } from 'fp-ts/lib/function'; import { errors as EsErrors } from '@elastic/elasticsearch'; import type { ElasticsearchClient, diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/create_index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/create_index.ts index aea970f1bf5f9b..0b38f9c369d5ff 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/create_index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/create_index.ts @@ -8,7 +8,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; -import { pipe } from 'fp-ts/lib/pipeable'; +import { pipe } from 'fp-ts/lib/function'; import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient, diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts index 79df66c4b9ccbb..84f37c96cca5fa 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts @@ -27,6 +27,9 @@ export { initAction } from './initialize_action'; export type { FetchIndexResponse, FetchIndicesParams } from './fetch_indices'; export { fetchIndices } from './fetch_indices'; +export type { SafeWriteBlockParams } from './safe_write_block'; +export { safeWriteBlock } from './safe_write_block'; + export type { SetWriteBlockParams } from './set_write_block'; export { setWriteBlock } from './set_write_block'; @@ -158,6 +161,11 @@ export interface EsResponseTooLargeError { contentLength: number; } +export interface SourceEqualsTarget { + type: 'source_equals_target'; + index: string; +} + /** @internal */ export interface AcknowledgeResponse { acknowledged: boolean; @@ -185,6 +193,7 @@ export interface ActionErrorTypeMap { index_mappings_incomplete: IndexMappingsIncomplete; types_changed: TypesChanged; operation_not_supported: OperationNotSupported; + source_equals_target: SourceEqualsTarget; } /** diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.ts index 8daa548039eeb8..7db32f7a67d99c 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.ts @@ -8,7 +8,7 @@ import * as TaskEither from 'fp-ts/lib/TaskEither'; import * as Either from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; +import { pipe } from 'fp-ts/lib/function'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { catchRetryableEsClientErrors, diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/safe_write_block.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/safe_write_block.test.ts new file mode 100644 index 00000000000000..40e60a7afd4c42 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/safe_write_block.test.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 * as Either from 'fp-ts/lib/Either'; +import * as TaskEither from 'fp-ts/lib/TaskEither'; +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import { safeWriteBlock } from './safe_write_block'; + +jest.mock('./set_write_block'); +import { setWriteBlock } from './set_write_block'; + +const setWriteBlockMock = setWriteBlock as jest.MockedFn; + +describe('safeWriteBlock', () => { + beforeEach(() => { + setWriteBlockMock.mockReset(); + setWriteBlockMock.mockReturnValueOnce( + TaskEither.fromEither(Either.right('set_write_block_succeeded' as const)) + ); + }); + + const client = elasticsearchClientMock.createInternalClient(); + it('returns a Left response if source and target indices match', async () => { + const task = safeWriteBlock({ + client, + sourceIndex: '.kibana_8.15.0_001', + targetIndex: '.kibana_8.15.0_001', + }); + const res = await task(); + expect(res).toEqual(Either.left({ type: 'source_equals_target', index: '.kibana_8.15.0_001' })); + expect(setWriteBlockMock).not.toHaveBeenCalled(); + }); + + it('calls setWriteBlock if indices are different', async () => { + const task = safeWriteBlock({ + client, + sourceIndex: '.kibana_7.13.0_001', + targetIndex: '.kibana_8.15.0_001', + timeout: '28s', + }); + const res = await task(); + expect(res).toEqual(Either.right('set_write_block_succeeded' as const)); + expect(setWriteBlockMock).toHaveBeenCalledTimes(1); + expect(setWriteBlockMock).toHaveBeenCalledWith({ + client, + index: '.kibana_7.13.0_001', + timeout: '28s', + }); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/safe_write_block.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/safe_write_block.ts new file mode 100644 index 00000000000000..cb1270428f5dd6 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/safe_write_block.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 * as Either from 'fp-ts/lib/Either'; +import * as TaskEither from 'fp-ts/lib/TaskEither'; +import { pipe } from 'fp-ts/lib/function'; +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { RetryableEsClientError } from './catch_retryable_es_client_errors'; +import { DEFAULT_TIMEOUT, type SourceEqualsTarget, type IndexNotFound } from '.'; +import { setWriteBlock } from './set_write_block'; + +/** @internal */ +export interface SafeWriteBlockParams { + client: ElasticsearchClient; + sourceIndex: string; + targetIndex: string; + timeout?: string; +} + +export const safeWriteBlock = ({ + client, + sourceIndex, + targetIndex, + timeout = DEFAULT_TIMEOUT, +}: SafeWriteBlockParams): TaskEither.TaskEither< + SourceEqualsTarget | IndexNotFound | RetryableEsClientError, + 'set_write_block_succeeded' +> => { + const assertSourceAndTargetDifferTask: TaskEither.TaskEither< + SourceEqualsTarget, + 'source_and_target_differ' + > = TaskEither.fromEither( + sourceIndex === targetIndex + ? Either.left({ type: 'source_equals_target' as const, index: sourceIndex }) + : Either.right('source_and_target_differ' as const) + ); + + return pipe( + assertSourceAndTargetDifferTask, + TaskEither.chainW(() => setWriteBlock({ client, index: sourceIndex, timeout })) + ); +}; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/update_and_pickup_mappings.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/update_and_pickup_mappings.ts index 8478ad08247a5a..9cd55f88a066c5 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/update_and_pickup_mappings.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/update_and_pickup_mappings.ts @@ -8,7 +8,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; -import { pipe } from 'fp-ts/lib/pipeable'; +import { pipe } from 'fp-ts/lib/function'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { IndexMapping } from '@kbn/core-saved-objects-base-server-internal'; import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/update_source_mappings_properties.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/update_source_mappings_properties.ts index 3a73f948efa20c..1a47992074af8a 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/update_source_mappings_properties.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/update_source_mappings_properties.ts @@ -8,7 +8,7 @@ import { omit } from 'lodash'; import * as TaskEither from 'fp-ts/lib/TaskEither'; -import { pipe } from 'fp-ts/lib/pipeable'; +import { pipe } from 'fp-ts/lib/function'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { IndexMapping, VirtualVersionMap } from '@kbn/core-saved-objects-base-server-internal'; import { diffMappings } from '../core/diff_mappings'; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts index f06e9f836f2c53..1980a6e6128db4 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts @@ -1645,6 +1645,15 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('SET_SOURCE_WRITE_BLOCK -> REFRESH_TARGET if source index matches target index', () => { + const index = `.kibana_${setWriteBlockState.kibanaVersion}_001`; + const res: ResponseType<'SET_SOURCE_WRITE_BLOCK'> = Either.left({ + type: 'source_equals_target' as const, + index, + }); + const newState = model(setWriteBlockState, res); + expect(newState.controlState).toEqual('REFRESH_TARGET'); + }); }); describe('CALCULATE_EXCLUDE_FILTERS', () => { diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts index e25d48af4ed25e..4f1f48444dc230 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts @@ -736,6 +736,14 @@ export const model = (currentState: State, resW: ResponseType): ...stateP, controlState: 'CALCULATE_EXCLUDE_FILTERS', }; + } else if (isTypeof(res.left, 'source_equals_target')) { + // As part of a reindex-migration, we wanted to block the source index to prevent updates + // However, this migrator's source index matches the target index. + // Thus, another instance's migrator is ahead of us. We skip the clone steps and continue the flow + return { + ...stateP, + controlState: 'REFRESH_TARGET', + }; } else if (isTypeof(res.left, 'index_not_found_exception')) { // We don't handle the following errors as the migration algorithm // will never cause them to occur: diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts index 9cd7f92ee4355b..9f7da4a10c2e81 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts @@ -125,7 +125,11 @@ export const nextActionMap = ( knownTypes: state.knownTypes, }), SET_SOURCE_WRITE_BLOCK: (state: SetSourceWriteBlockState) => - Actions.setWriteBlock({ client, index: state.sourceIndex.value }), + Actions.safeWriteBlock({ + client, + sourceIndex: state.sourceIndex.value, + targetIndex: state.targetIndex, + }), CALCULATE_EXCLUDE_FILTERS: (state: CalculateExcludeFiltersState) => Actions.calculateExcludeFilters({ client, From 52e678a0aa95d5770fe1338d9f1475251499d346 Mon Sep 17 00:00:00 2001 From: jennypavlova Date: Wed, 19 Jun 2024 10:56:43 +0200 Subject: [PATCH 078/123] [Infra] Logs tab in container views should use container id (#186393) Closes #186392 ## Summary This PR fixes a bug with the Logs Tab in asset details using asset name instead of id. https://github.com/elastic/kibana/assets/14139027/19d4531c-fd9f-4327-ae2c-438fdcbb91f1 ## Testing - Check the logs tab in the asset details view for a container - Check the Open in Logs Stream link - It should show `container.id: {container.id}` as filter image - Check the logs tab in the asset details view for a host - Check the Open in Logs Stream link - It should show `host.name: {host.name}` as filter image --- .../public/components/asset_details/tabs/logs/logs.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/logs/logs.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/logs/logs.tsx index a8236069fe3a7f..72ad37ce1cfda1 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/logs/logs.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/logs/logs.tsx @@ -60,7 +60,7 @@ export const Logs = () => { const filter = useMemo(() => { const query = [ - `${findInventoryFields(asset.type).id}: "${asset.name}"`, + `${findInventoryFields(asset.type).id}: "${asset.id}"`, ...(textQueryDebounced !== '' ? [textQueryDebounced] : []), ].join(' and '); @@ -68,7 +68,7 @@ export const Logs = () => { language: 'kuery', query, }; - }, [asset.type, asset.name, textQueryDebounced]); + }, [asset.type, asset.id, textQueryDebounced]); const onQueryChange = useCallback((e: React.ChangeEvent) => { setTextQuery(e.target.value); @@ -82,12 +82,12 @@ export const Logs = () => { const logsUrl = useMemo(() => { return nodeLogsLocator.getRedirectUrl({ nodeField: findInventoryFields(asset.type).id, - nodeId: asset.name, + nodeId: asset.id, time: state.startTimestamp, filter: textQueryDebounced, logView, }); - }, [nodeLogsLocator, asset.name, asset.type, state.startTimestamp, textQueryDebounced, logView]); + }, [nodeLogsLocator, asset.id, asset.type, state.startTimestamp, textQueryDebounced, logView]); return ( From 85f67dd39ae7b4a3f8b96bdf8a3d421b67f6f45f Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Wed, 19 Jun 2024 11:04:33 +0200 Subject: [PATCH 079/123] Implement `elasticsearch.maxResponseSize` config option (#186291) ## Summary Fix https://github.com/elastic/kibana/issues/185042 - Add a new `elasticsearch.maxResponseSize` config option - Set this value to `100mb` on our serverless configuration file --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- config/serverless.yml | 3 + docs/setup/settings.asciidoc | 4 + .../src/client_config.test.ts | 24 +++++ .../src/client_config.ts | 5 ++ .../src/create_transport.test.ts | 73 +++++++++++++++ .../src/create_transport.ts | 14 +++ .../src/log_query_and_deprecation.test.ts | 37 ++++++++ .../src/log_query_and_deprecation.ts | 17 +++- .../tsconfig.json | 1 + .../src/elasticsearch_config.test.ts | 15 ++++ .../src/elasticsearch_config.ts | 17 +++- .../src/client/client_config.ts | 2 + .../core-elasticsearch-server/tsconfig.json | 3 +- packages/kbn-es-errors/index.ts | 7 +- packages/kbn-es-errors/src/errors.test.ts | 40 ++++++++- packages/kbn-es-errors/src/errors.ts | 14 +++ .../max_response_size_logging.test.ts | 89 +++++++++++++++++++ .../plugins/monitoring/server/config.test.ts | 1 + 18 files changed, 359 insertions(+), 7 deletions(-) create mode 100644 src/core/server/integration_tests/elasticsearch/max_response_size_logging.test.ts diff --git a/config/serverless.yml b/config/serverless.yml index cb4bbac7c92faf..6658eba7095c16 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -70,6 +70,9 @@ core.lifecycle.disablePreboot: true # Enable ZDT migration algorithm migrations.algorithm: zdt +# Enable elasticsearch response size circuit breaker +elasticsearch.maxResponseSize: "100mb" + # Limit batch size to reduce possibility of failures. # A longer migration time is acceptable due to the ZDT algorithm. migrations.batchSize: 250 diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 4405b746ca34f1..cb096ec127154e 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -89,6 +89,10 @@ configuration is effectively ignored when <> is enable The maximum number of sockets that can be used for communications with {es}. *Default: `Infinity`* +[[elasticsearch-maxResponseSize]] `elasticsearch.maxResponseSize`:: +Either `false` or a `byteSize` value. When set, responses from {es} with a size higher than the defined limit will be rejected. +This is intended to be used as a circuit-breaker mechanism to avoid memory errors in case of unexpectedly high responses coming from {es}. +*Default: `false`* [[elasticsearch-maxIdleSockets]] `elasticsearch.maxIdleSockets`:: The maximum number of idle sockets to keep open between {kib} and {es}. If more sockets become idle, they will be closed. diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/client_config.test.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/client_config.test.ts index b6526cc201717c..de0702b62aa66e 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/client_config.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/client_config.test.ts @@ -7,6 +7,7 @@ */ import { duration } from 'moment'; +import { ByteSizeValue } from '@kbn/config-schema'; import type { ElasticsearchClientConfig } from '@kbn/core-elasticsearch-server'; import { parseClientOptions } from './client_config'; import { getDefaultHeaders } from './headers'; @@ -19,6 +20,7 @@ const createConfig = ( compression: false, maxSockets: Infinity, maxIdleSockets: 300, + maxResponseSize: undefined, idleSocketTimeout: duration(30, 'seconds'), sniffOnStart: false, sniffOnConnectionFault: false, @@ -152,6 +154,28 @@ describe('parseClientOptions', () => { }); }); + describe('`maxResponseSize` option', () => { + it('does not set the values on client options when undefined', () => { + const options = parseClientOptions( + createConfig({ maxResponseSize: undefined }), + false, + kibanaVersion + ); + expect(options.maxResponseSize).toBe(undefined); + expect(options.maxCompressedResponseSize).toBe(undefined); + }); + + it('sets the right values on client options when defined', () => { + const options = parseClientOptions( + createConfig({ maxResponseSize: ByteSizeValue.parse('2kb') }), + false, + kibanaVersion + ); + expect(options.maxResponseSize).toBe(2048); + expect(options.maxCompressedResponseSize).toBe(2048); + }); + }); + describe('`compression` option', () => { it('`compression` is true', () => { const options = parseClientOptions( diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/client_config.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/client_config.ts index 58660a99173483..7310cdc2da7cde 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/client_config.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/client_config.ts @@ -47,6 +47,11 @@ export function parseClientOptions( compression: config.compression, }; + if (config.maxResponseSize) { + clientOptions.maxResponseSize = config.maxResponseSize.getValueInBytes(); + clientOptions.maxCompressedResponseSize = config.maxResponseSize.getValueInBytes(); + } + if (config.pingTimeout != null) { clientOptions.pingTimeout = getDurationAsMs(config.pingTimeout); } diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/create_transport.test.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/create_transport.test.ts index ce54d8356f38be..3039119ae3c16b 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/create_transport.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/create_transport.test.ts @@ -265,6 +265,79 @@ describe('createTransport', () => { ); }); }); + + describe('maxResponseSize options', () => { + it('does not set values when not provided in the options', async () => { + const transportClass = createTransportClass(); + const transport = new transportClass(baseConstructorParams); + const requestParams = { method: 'GET', path: '/' }; + + await transport.request(requestParams, {}); + + expect(transportRequestMock).toHaveBeenCalledTimes(1); + expect(transportRequestMock).toHaveBeenCalledWith( + expect.any(Object), + expect.not.objectContaining({ + maxResponseSize: expect.any(Number), + maxCompressedResponseSize: expect.any(Number), + }) + ); + }); + + it('uses `maxResponseSize` from the options when provided and when `maxCompressedResponseSize` is not', async () => { + const transportClass = createTransportClass(); + const transport = new transportClass(baseConstructorParams); + const requestParams = { method: 'GET', path: '/' }; + + await transport.request(requestParams, { maxResponseSize: 234 }); + + expect(transportRequestMock).toHaveBeenCalledTimes(1); + expect(transportRequestMock).toHaveBeenCalledWith( + expect.any(Object), + expect.objectContaining({ + maxResponseSize: 234, + maxCompressedResponseSize: 234, + }) + ); + }); + + it('uses `maxCompressedResponseSize` from the options when provided and when `maxResponseSize` is not', async () => { + const transportClass = createTransportClass(); + const transport = new transportClass(baseConstructorParams); + const requestParams = { method: 'GET', path: '/' }; + + await transport.request(requestParams, { maxCompressedResponseSize: 272 }); + + expect(transportRequestMock).toHaveBeenCalledTimes(1); + expect(transportRequestMock).toHaveBeenCalledWith( + expect.any(Object), + expect.objectContaining({ + maxResponseSize: 272, + maxCompressedResponseSize: 272, + }) + ); + }); + + it('uses individual values when both `maxResponseSize` and `maxCompressedResponseSize` are defined', async () => { + const transportClass = createTransportClass(); + const transport = new transportClass(baseConstructorParams); + const requestParams = { method: 'GET', path: '/' }; + + await transport.request(requestParams, { + maxResponseSize: 512, + maxCompressedResponseSize: 272, + }); + + expect(transportRequestMock).toHaveBeenCalledTimes(1); + expect(transportRequestMock).toHaveBeenCalledWith( + expect.any(Object), + expect.objectContaining({ + maxResponseSize: 512, + maxCompressedResponseSize: 272, + }) + ); + }); + }); }); describe('unauthorized error handler', () => { diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/create_transport.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/create_transport.ts index 07ed3833a7af21..ef643faa05c178 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/create_transport.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/create_transport.ts @@ -41,6 +41,20 @@ export const createTransport = ({ async request(params: TransportRequestParams, options?: TransportRequestOptions) { const opts: TransportRequestOptions = options ? { ...options } : {}; + // sync override of maxResponseSize and maxCompressedResponseSize + if (options) { + if ( + options.maxResponseSize !== undefined && + options.maxCompressedResponseSize === undefined + ) { + opts.maxCompressedResponseSize = options.maxResponseSize; + } else if ( + options.maxCompressedResponseSize !== undefined && + options.maxResponseSize === undefined + ) { + opts.maxResponseSize = options.maxCompressedResponseSize; + } + } const opaqueId = getExecutionContext(); if (opaqueId && !opts.opaqueId) { // rewrites headers['x-opaque-id'] if it presents diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/log_query_and_deprecation.test.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/log_query_and_deprecation.test.ts index edb3ab90e6bc69..e974951da8aefa 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/log_query_and_deprecation.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/log_query_and_deprecation.test.ts @@ -1051,4 +1051,41 @@ describe('instrumentQueryAndDeprecationLogger', () => { }); }); }); + + describe('requests aborted due to maximum response size exceeded errors', () => { + const requestAbortedErrorMessage = `The content length (9000) is bigger than the maximum allowed buffer (42)`; + + it('logs warning when the client emits a RequestAbortedError error due to excessive response length ', () => { + instrumentEsQueryAndDeprecationLogger({ + logger, + client, + type: 'test type', + apisToRedactInLogs: [], + }); + + client.diagnostic.emit( + 'response', + new errors.RequestAbortedError(requestAbortedErrorMessage), + null + ); + + expect(loggingSystemMock.collect(logger).warn[0][0]).toMatchInlineSnapshot( + `"Request was aborted: The content length (9000) is bigger than the maximum allowed buffer (42)"` + ); + }); + + it('does not log warning for other type of errors', () => { + instrumentEsQueryAndDeprecationLogger({ + logger, + client, + type: 'test type', + apisToRedactInLogs: [], + }); + + const response = createApiResponse({ body: {} }); + client.diagnostic.emit('response', new errors.TimeoutError('message', response), response); + + expect(loggingSystemMock.collect(logger).warn).toMatchInlineSnapshot(`Array []`); + }); + }); }); diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/log_query_and_deprecation.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/log_query_and_deprecation.ts index 8d7f0f0a5c2dd4..753b17a6a7aa33 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/log_query_and_deprecation.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/log_query_and_deprecation.ts @@ -12,7 +12,7 @@ import { stringify } from 'querystring'; import { errors, DiagnosticResult, RequestBody, Client } from '@elastic/elasticsearch'; import numeral from '@elastic/numeral'; import type { Logger } from '@kbn/logging'; -import type { ElasticsearchErrorDetails } from '@kbn/es-errors'; +import { isMaximumResponseSizeExceededError, type ElasticsearchErrorDetails } from '@kbn/es-errors'; import type { ElasticsearchApiToRedactInLogs } from '@kbn/core-elasticsearch-server'; import { getEcsResponseLog } from './get_ecs_response_log'; @@ -171,6 +171,16 @@ function getQueryMessage( } } +function getResponseSizeExceededErrorMessage(error: errors.RequestAbortedError): string { + if (error.meta) { + const params = error.meta.meta.request.params; + return `Request against ${params.method} ${params.path} was aborted: ${error.message}`; + } else { + // in theory meta is always populated for such errors, but better safe than sorry + return `Request was aborted: ${error.message}`; + } +} + export const instrumentEsQueryAndDeprecationLogger = ({ logger, client, @@ -184,6 +194,7 @@ export const instrumentEsQueryAndDeprecationLogger = ({ }) => { const queryLogger = logger.get('query', type); const deprecationLogger = logger.get('deprecation'); + const warningLogger = logger.get('warnings'); // elasticsearch.warnings client.diagnostic.on('response', (error, event) => { // we could check this once and not subscribe to response events if both are disabled, @@ -191,6 +202,10 @@ export const instrumentEsQueryAndDeprecationLogger = ({ const logQuery = queryLogger.isLevelEnabled('debug'); const logDeprecation = deprecationLogger.isLevelEnabled('debug'); + if (error && isMaximumResponseSizeExceededError(error)) { + warningLogger.warn(getResponseSizeExceededErrorMessage(error)); + } + if (event && (logQuery || logDeprecation)) { const bytes = getContentLength(event.headers); const queryMsg = getQueryMessage(bytes, error, event, apisToRedactInLogs); diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/tsconfig.json b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/tsconfig.json index 2288caa55dea82..de4169d034e651 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/tsconfig.json +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/tsconfig.json @@ -22,6 +22,7 @@ "@kbn/core-logging-server-mocks", "@kbn/core-http-server-mocks", "@kbn/core-metrics-server", + "@kbn/config-schema", ], "exclude": [ "target/**/*", diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.test.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.test.ts index 58745a0e85d094..cafa50e65d91c5 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.test.ts @@ -42,6 +42,7 @@ test('set correct defaults', () => { "idleSocketTimeout": "PT1M", "ignoreVersionMismatch": false, "maxIdleSockets": 256, + "maxResponseSize": undefined, "maxSockets": 800, "password": undefined, "pingTimeout": "PT30S", @@ -127,6 +128,20 @@ describe('#maxSockets', () => { }); }); +describe('#maxResponseSize', () => { + test('accepts `false` value', () => { + const configValue = new ElasticsearchConfig(config.schema.validate({ maxResponseSize: false })); + expect(configValue.maxResponseSize).toBe(undefined); + }); + + test('accepts bytesize value', () => { + const configValue = new ElasticsearchConfig( + config.schema.validate({ maxResponseSize: '200b' }) + ); + expect(configValue.maxResponseSize!.getValueInBytes()).toBe(200); + }); +}); + test('#requestHeadersWhitelist accepts both string and array of strings', () => { let configValue = new ElasticsearchConfig( config.schema.validate({ requestHeadersWhitelist: 'token' }) diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.ts index 1f6d75b2f30e19..010bc3ac1c7961 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_config.ts @@ -6,11 +6,11 @@ * Side Public License, v 1. */ -import { schema, TypeOf, offeringBasedSchema } from '@kbn/config-schema'; +import { readFileSync } from 'fs'; +import { Duration } from 'moment'; import { readPkcs12Keystore, readPkcs12Truststore } from '@kbn/crypto'; import { i18n } from '@kbn/i18n'; -import { Duration } from 'moment'; -import { readFileSync } from 'fs'; +import { schema, offeringBasedSchema, ByteSizeValue, type TypeOf } from '@kbn/config-schema'; import type { ServiceConfigDescriptor } from '@kbn/core-base-server-internal'; import type { ConfigDeprecationProvider } from '@kbn/config'; import type { @@ -42,6 +42,9 @@ export const configSchema = schema.object({ }), maxSockets: schema.number({ defaultValue: 800, min: 1 }), maxIdleSockets: schema.number({ defaultValue: 256, min: 1 }), + maxResponseSize: schema.oneOf([schema.literal(false), schema.byteSize()], { + defaultValue: false, + }), idleSocketTimeout: schema.duration({ defaultValue: '60s' }), compression: schema.boolean({ defaultValue: false }), username: schema.maybe( @@ -332,6 +335,12 @@ export class ElasticsearchConfig implements IElasticsearchConfig { */ public readonly maxIdleSockets: number; + /** + * The maximum allowed response size (both compressed and uncompressed). + * When defined, responses with a size higher than the set limit will be aborted with an error. + */ + public readonly maxResponseSize?: ByteSizeValue; + /** * The timeout for idle sockets kept open between Kibana and Elasticsearch. If the socket is idle for longer than this timeout, it will be closed. */ @@ -455,6 +464,8 @@ export class ElasticsearchConfig implements IElasticsearchConfig { this.customHeaders = rawConfig.customHeaders; this.maxSockets = rawConfig.maxSockets; this.maxIdleSockets = rawConfig.maxIdleSockets; + this.maxResponseSize = + rawConfig.maxResponseSize !== false ? rawConfig.maxResponseSize : undefined; this.idleSocketTimeout = rawConfig.idleSocketTimeout; this.compression = rawConfig.compression; this.skipStartupConnectionCheck = rawConfig.skipStartupConnectionCheck; diff --git a/packages/core/elasticsearch/core-elasticsearch-server/src/client/client_config.ts b/packages/core/elasticsearch/core-elasticsearch-server/src/client/client_config.ts index 6ef638525c5801..e7d119a90622d4 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server/src/client/client_config.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server/src/client/client_config.ts @@ -7,6 +7,7 @@ */ import type { Duration } from 'moment'; +import type { ByteSizeValue } from '@kbn/config-schema'; /** * Definition of an API that should redact the requested body in the logs @@ -35,6 +36,7 @@ export interface ElasticsearchClientConfig { requestHeadersWhitelist: string[]; maxSockets: number; maxIdleSockets: number; + maxResponseSize?: ByteSizeValue; idleSocketTimeout: Duration; compression: boolean; sniffOnStart: boolean; diff --git a/packages/core/elasticsearch/core-elasticsearch-server/tsconfig.json b/packages/core/elasticsearch/core-elasticsearch-server/tsconfig.json index 88e18c12e41e09..c3320c12cff9bb 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server/tsconfig.json +++ b/packages/core/elasticsearch/core-elasticsearch-server/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/es-errors", - "@kbn/core-http-server" + "@kbn/core-http-server", + "@kbn/config-schema" ], "exclude": [ "target/**/*", diff --git a/packages/kbn-es-errors/index.ts b/packages/kbn-es-errors/index.ts index 0d5b6007e5cc8d..b5e18f6206474e 100644 --- a/packages/kbn-es-errors/index.ts +++ b/packages/kbn-es-errors/index.ts @@ -7,5 +7,10 @@ */ export type { ElasticsearchErrorDetails } from './src/types'; -export { isUnauthorizedError, isResponseError } from './src/errors'; +export { + isUnauthorizedError, + isResponseError, + isRequestAbortedError, + isMaximumResponseSizeExceededError, +} from './src/errors'; export type { UnauthorizedError } from './src/errors'; diff --git a/packages/kbn-es-errors/src/errors.test.ts b/packages/kbn-es-errors/src/errors.test.ts index 59c4296d2bbb28..6a6384585f5a9b 100644 --- a/packages/kbn-es-errors/src/errors.test.ts +++ b/packages/kbn-es-errors/src/errors.test.ts @@ -8,7 +8,12 @@ import { errors } from '@elastic/elasticsearch'; import type { TransportResult } from '@elastic/elasticsearch'; -import { isResponseError, isUnauthorizedError } from './errors'; +import { + isResponseError, + isUnauthorizedError, + isRequestAbortedError, + isMaximumResponseSizeExceededError, +} from './errors'; const createApiResponseError = ({ statusCode = 200, @@ -69,3 +74,36 @@ describe('isUnauthorizedError', () => { expect(isUnauthorizedError(new errors.ConfigurationError('foo'))).toBe(false); }); }); + +describe('isRequestAbortedError', () => { + it('returns `true` when the input is a `RequestAbortedError`', () => { + expect(isRequestAbortedError(new errors.RequestAbortedError('Oh no'))).toBe(true); + }); + it('returns `false` when the input is not a `RequestAbortedError`', () => { + expect( + isRequestAbortedError(new errors.ResponseError(createApiResponseError({ statusCode: 500 }))) + ).toBe(false); + }); +}); + +describe('isMaximumResponseSizeExceededError', () => { + it('returns `true` when the input is a `RequestAbortedError` with the right message', () => { + expect( + isMaximumResponseSizeExceededError( + new errors.RequestAbortedError( + `The content length (9000) is bigger than the maximum allowed buffer (42)` + ) + ) + ).toBe(true); + }); + it('returns `false` when the input is a `RequestAbortedError` without the right message', () => { + expect(isMaximumResponseSizeExceededError(new errors.RequestAbortedError('Oh no'))).toBe(false); + }); + it('returns `false` when the input is not a `RequestAbortedError`', () => { + expect( + isMaximumResponseSizeExceededError( + new errors.ResponseError(createApiResponseError({ statusCode: 500 })) + ) + ).toBe(false); + }); +}); diff --git a/packages/kbn-es-errors/src/errors.ts b/packages/kbn-es-errors/src/errors.ts index d46097eb95a2b8..24e314f084b59b 100644 --- a/packages/kbn-es-errors/src/errors.ts +++ b/packages/kbn-es-errors/src/errors.ts @@ -31,3 +31,17 @@ export function isResponseError(error: unknown): error is errors.ResponseError { export function isUnauthorizedError(error: unknown): error is UnauthorizedError { return isResponseError(error) && error.statusCode === 401; } + +/** + * Checks if the provided `error` is an {@link errors.RequestAbortedError | elasticsearch request aborted error} + * @public + */ +export function isRequestAbortedError(error: unknown): error is errors.RequestAbortedError { + return error instanceof errors.RequestAbortedError; +} + +export function isMaximumResponseSizeExceededError( + error: unknown +): error is errors.RequestAbortedError { + return isRequestAbortedError(error) && error.message.includes('content length'); +} diff --git a/src/core/server/integration_tests/elasticsearch/max_response_size_logging.test.ts b/src/core/server/integration_tests/elasticsearch/max_response_size_logging.test.ts new file mode 100644 index 00000000000000..d9d6cda70c74c2 --- /dev/null +++ b/src/core/server/integration_tests/elasticsearch/max_response_size_logging.test.ts @@ -0,0 +1,89 @@ +/* + * 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 { + createTestServers, + type TestElasticsearchUtils, + type TestKibanaUtils, +} from '@kbn/core-test-helpers-kbn-server'; +import { unsafeConsole } from '@kbn/security-hardening'; + +describe('Elasticsearch max response size', () => { + let mockConsoleLog: jest.SpyInstance; + let esServer: TestElasticsearchUtils; + let kibanaServer: TestKibanaUtils; + + beforeAll(async () => { + mockConsoleLog = jest.spyOn(unsafeConsole, 'log'); + + const { startES, startKibana } = createTestServers({ + adjustTimeout: jest.setTimeout, + settings: { + kbn: { + logging: { + appenders: { + 'test-appender': { + type: 'console', + layout: { + type: 'pattern', + }, + }, + }, + loggers: [ + { name: 'elasticsearch.warnings', appenders: ['test-appender'], level: 'info' }, + ], + }, + }, + }, + }); + + esServer = await startES(); + kibanaServer = await startKibana(); + }); + + beforeEach(() => { + mockConsoleLog.mockClear(); + }); + + afterAll(async () => { + mockConsoleLog.mockRestore(); + await kibanaServer.stop(); + await esServer.stop(); + }); + + it('rejects the response when the response size is larger than the requested limit', async () => { + const esClient = kibanaServer.coreStart.elasticsearch.client.asInternalUser; + + try { + await esClient.cluster.stats({}, { maxResponseSize: 200 }); + expect('should have thrown').toEqual('but it did not'); + } catch (e) { + expect(e.name).toEqual('RequestAbortedError'); + expect(e.message).toContain('is bigger than the maximum allowed string (200)'); + } + }); + + it('logs a warning with the expected message', async () => { + const esClient = kibanaServer.coreStart.elasticsearch.client.asInternalUser; + + try { + await esClient.cluster.stats({}, { maxResponseSize: 200 }); + expect('should have thrown').toEqual('but it did not'); + } catch (e) { + const calls = mockConsoleLog.mock.calls; + + const warningCall = calls + .map((call) => call[0]) + .find((call) => call.includes('elasticsearch.warnings')); + expect(warningCall).toContain( + 'Request against GET /_cluster/stats was aborted: The content length' + ); + expect(warningCall).toContain('is bigger than the maximum allowed string (200)'); + } + }); +}); diff --git a/x-pack/plugins/monitoring/server/config.test.ts b/x-pack/plugins/monitoring/server/config.test.ts index ddaabf7bef2c79..bde75fe4138eeb 100644 --- a/x-pack/plugins/monitoring/server/config.test.ts +++ b/x-pack/plugins/monitoring/server/config.test.ts @@ -69,6 +69,7 @@ describe('config schema', () => { "logFetchCount": 10, "logQueries": false, "maxIdleSockets": 256, + "maxResponseSize": false, "maxSockets": 800, "pingTimeout": "PT30S", "requestHeadersWhitelist": Array [ From 771c9545201a3a87163fb0a7c1f58357b206780c Mon Sep 17 00:00:00 2001 From: elena-shostak <165678770+elena-shostak@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:24:35 +0200 Subject: [PATCH 080/123] [Feature Controls] Added a filter_path to the /_xpack/usage ES call (#186370) ## Summary Calls to `/_xpack/usage` in Elasticsearch do not perform well on large clusters. See https://github.com/elastic/elasticsearch/issues/100230. Some users have reported timeouts on this request path. Added a filter_path to the `/_xpack/usage` ES call to optimize the call. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) __Fixes: https://github.com/elastic/kibana/issues/169449__ Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/routes/feature_check/feature_check.test.ts | 9 +++++++++ .../server/routes/feature_check/feature_check.ts | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security/server/routes/feature_check/feature_check.test.ts b/x-pack/plugins/security/server/routes/feature_check/feature_check.test.ts index 953f65afa9a7ca..a1745ec0930b4e 100644 --- a/x-pack/plugins/security/server/routes/feature_check/feature_check.test.ts +++ b/x-pack/plugins/security/server/routes/feature_check/feature_check.test.ts @@ -86,6 +86,15 @@ describe('GET role mappings feature check', () => { expect(response.payload).toEqual(asserts.result); expect(mockLicensingContext.license.check).toHaveBeenCalledWith('security', 'basic'); + + if (canReadSecurity) { + expect( + mockCoreContext.elasticsearch.client.asInternalUser.transport.request + ).toHaveBeenCalledWith({ + method: 'GET', + path: '/_xpack/usage?filter_path=remote_clusters.*,security.realms.*', + }); + } }); }; diff --git a/x-pack/plugins/security/server/routes/feature_check/feature_check.ts b/x-pack/plugins/security/server/routes/feature_check/feature_check.ts index 442f040398962d..46276957b6c838 100644 --- a/x-pack/plugins/security/server/routes/feature_check/feature_check.ts +++ b/x-pack/plugins/security/server/routes/feature_check/feature_check.ts @@ -88,7 +88,10 @@ async function getEnabledSecurityFeatures(esClient: ElasticsearchClient, logger: // `transport.request` is potentially unsafe when combined with untrusted user input. // Do not augment with such input. const xpackUsagePromise = esClient.transport - .request({ method: 'GET', path: '/_xpack/usage' }) + .request({ + method: 'GET', + path: '/_xpack/usage?filter_path=remote_clusters.*,security.realms.*', + }) .then((body) => body as XPackUsageResponse) .catch((error) => { // fall back to no external realms configured. From a7ffdf87c13cf3c99e973805e612fc6fa25e1689 Mon Sep 17 00:00:00 2001 From: Tre Date: Wed, 19 Jun 2024 10:35:15 +0100 Subject: [PATCH 081/123] [fix on mki] dismiss all toasts before deleting (#186406) ## Summary See details: https://github.com/elastic/kibana/issues/186403 Fixes: https://github.com/elastic/kibana/issues/186403 --- x-pack/test/functional/services/cases/list.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/test/functional/services/cases/list.ts b/x-pack/test/functional/services/cases/list.ts index b449b6f18438aa..34db5e7345b3c4 100644 --- a/x-pack/test/functional/services/cases/list.ts +++ b/x-pack/test/functional/services/cases/list.ts @@ -24,6 +24,7 @@ export function CasesTableServiceProvider( const browser = getService('browser'); const retry = getService('retry'); const config = getService('config'); + const toasts = getService('toasts'); const assertCaseExists = (index: number, totalCases: number) => { if (index > totalCases - 1) { @@ -49,6 +50,7 @@ export function CasesTableServiceProvider( }, async deleteCase(index: number = 0) { + await toasts.dismissAll(); this.openRowActions(index); await testSubjects.existOrFail('cases-bulk-action-delete'); await testSubjects.click('cases-bulk-action-delete'); From 8a7de8c113f7e45a5f92ea111901a7b0af15c520 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Wed, 19 Jun 2024 10:39:08 +0100 Subject: [PATCH 082/123] [Security Solution][Detection Engine] unskips FTR user roles tests (#186276) ## Summary - addresses https://github.com/elastic/kibana/issues/174028 - checked locally with the [latest main(8.15 snapshot)](https://buildkite.com/elastic/kibana-elasticsearch-snapshot-verify/builds/4126) --- .../user_roles/trial_license_complete_tier/read_privileges.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/user_roles/trial_license_complete_tier/read_privileges.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/user_roles/trial_license_complete_tier/read_privileges.ts index 7727958243823e..51a7a9ab1330f7 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/user_roles/trial_license_complete_tier/read_privileges.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/user_roles/trial_license_complete_tier/read_privileges.ts @@ -19,8 +19,7 @@ export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - // Failing ES Promotion: https://github.com/elastic/kibana/issues/174028 - describe.skip('@ess @serverless @skipInServerless read_privileges', () => { + describe('@ess @serverless @skipInServerless read_privileges', () => { it('should return expected privileges for elastic admin', async () => { const { body } = await supertest.get(DETECTION_ENGINE_PRIVILEGES_URL).send().expect(200); expect(body).to.eql({ From ca083d27355b82495965003727242a1afcdafd5d Mon Sep 17 00:00:00 2001 From: Abdul Wahab Zahid Date: Wed, 19 Jun 2024 11:48:48 +0200 Subject: [PATCH 083/123] [Dataset quality] Prevent an extra call to ES for degraded docs (#185975) The PR prevents an extra call to ES, thus improving the response time the endpoint `/internal/dataset_quality/data_streams/degraded_docs` takes. **Before** prevent-extra-call-before **After** ![prevent-extra-call-after](https://github.com/elastic/kibana/assets/2748376/312b2600-f5a5-4865-8ba4-9a54f0f52317) --- .../routes/data_streams/get_degraded_docs.ts | 17 +- .../tests/data_streams/degraded_docs.spec.ts | 174 +++++++++++++++++- 2 files changed, 181 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_degraded_docs.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_degraded_docs.ts index bba1f1dce3ec5a..fa876d047abd70 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_degraded_docs.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_degraded_docs.ts @@ -23,6 +23,8 @@ interface ResultBucket { count: number; } +const SIZE_LIMIT = 10000; + export async function getDegradedDocsPaginated(options: { esClient: ElasticsearchClient; type?: DataStreamType; @@ -65,7 +67,7 @@ export async function getDegradedDocsPaginated(options: { datasets: { composite: { ...(afterKey ? { after: afterKey } : {}), - size: 10000, + size: SIZE_LIMIT, sources: [ { dataset: { terms: { field: 'data_stream.dataset' } } }, { namespace: { terms: { field: 'data_stream.namespace' } } }, @@ -99,9 +101,10 @@ export async function getDegradedDocsPaginated(options: { aggs: aggs(after?.docsCount), }, ]); + const [degradedDocsResponse, totalDocsResponse] = response.responses; const currDegradedDocs = - response.responses[0].aggregations?.datasets.buckets.map((bucket) => ({ + degradedDocsResponse.aggregations?.datasets.buckets.map((bucket) => ({ dataset: `${type}-${bucket.key.dataset}-${bucket.key.namespace}`, count: bucket.doc_count, })) ?? []; @@ -109,7 +112,7 @@ export async function getDegradedDocsPaginated(options: { const degradedDocs = [...prevResults.degradedDocs, ...currDegradedDocs]; const currTotalDocs = - response.responses[1].aggregations?.datasets.buckets.map((bucket) => ({ + totalDocsResponse.aggregations?.datasets.buckets.map((bucket) => ({ dataset: `${type}-${bucket.key.dataset}-${bucket.key.namespace}`, count: bucket.doc_count, })) ?? []; @@ -117,8 +120,8 @@ export async function getDegradedDocsPaginated(options: { const docsCount = [...prevResults.docsCount, ...currTotalDocs]; if ( - response.responses[0].aggregations?.datasets.after_key || - response.responses[1].aggregations?.datasets.after_key + totalDocsResponse.aggregations?.datasets.after_key && + totalDocsResponse.aggregations?.datasets.buckets.length === SIZE_LIMIT ) { return getDegradedDocsPaginated({ esClient, @@ -128,12 +131,12 @@ export async function getDegradedDocsPaginated(options: { datasetQuery, after: { degradedDocs: - (response.responses[0].aggregations?.datasets.after_key as { + (degradedDocsResponse.aggregations?.datasets.after_key as { dataset: string; namespace: string; }) || after?.degradedDocs, docsCount: - (response.responses[1].aggregations?.datasets.after_key as { + (totalDocsResponse.aggregations?.datasets.after_key as { dataset: string; namespace: string; }) || after?.docsCount, diff --git a/x-pack/test/dataset_quality_api_integration/tests/data_streams/degraded_docs.spec.ts b/x-pack/test/dataset_quality_api_integration/tests/data_streams/degraded_docs.spec.ts index 0a8a993ecc4162..149f07a98a2f33 100644 --- a/x-pack/test/dataset_quality_api_integration/tests/data_streams/degraded_docs.spec.ts +++ b/x-pack/test/dataset_quality_api_integration/tests/data_streams/degraded_docs.spec.ts @@ -65,9 +65,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { .message('This is a log message') .timestamp(timestamp) .dataset('synth.2') - .logLevel( - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?' - ) + .logLevel(MORE_THAN_1024_CHARS) .defaults({ 'log.file.path': '/my-service.log', }) @@ -112,5 +110,175 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(stats.body.degradedDocs.length).to.be(0); }); }); + + describe('when there are data streams of different spaces', () => { + const spaces = ['default', 'space1', 'space2']; + const datasetsWithNoDegradedDocs = ['nginx.access', 'apache.access', 'mysql.access']; + const datasetsWithDegradedDocs = ['nginx.error', 'apache.error', 'mysql.error']; + + before(async () => { + for (const space of spaces) { + for (const dataset of datasetsWithNoDegradedDocs) { + await synthtrace.index([ + timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset(dataset) + .namespace(space) + ), + ]); + } + + for (const dataset of datasetsWithDegradedDocs) { + await synthtrace.index([ + timerange(start, end) + .interval('1m') + .rate(2) + .generator((timestamp: number, index: number) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset(dataset) + .namespace(space) + .logLevel(index % 2 === 0 ? MORE_THAN_1024_CHARS : 'This is a log message') + ), + ]); + } + } + }); + + it('returns counts and list of datasets correctly', async () => { + const stats = await callApiAs('datasetQualityLogsUser'); + expect(stats.body.degradedDocs.length).to.be(18); + + const expected = { + degradedDocs: [ + { + dataset: 'logs-apache.access-default', + count: 0, + docsCount: 1, + percentage: 0, + }, + { + dataset: 'logs-apache.access-space1', + count: 0, + docsCount: 1, + percentage: 0, + }, + { + dataset: 'logs-apache.access-space2', + count: 0, + docsCount: 1, + percentage: 0, + }, + { + dataset: 'logs-apache.error-default', + count: 1, + docsCount: 2, + percentage: 50, + }, + { + dataset: 'logs-apache.error-space1', + count: 1, + docsCount: 2, + percentage: 50, + }, + { + dataset: 'logs-apache.error-space2', + count: 1, + docsCount: 2, + percentage: 50, + }, + { + dataset: 'logs-mysql.access-default', + count: 0, + docsCount: 1, + percentage: 0, + }, + { + dataset: 'logs-mysql.access-space1', + count: 0, + docsCount: 1, + percentage: 0, + }, + { + dataset: 'logs-mysql.access-space2', + count: 0, + docsCount: 1, + percentage: 0, + }, + { + dataset: 'logs-mysql.error-default', + count: 1, + docsCount: 2, + percentage: 50, + }, + { + dataset: 'logs-mysql.error-space1', + count: 1, + docsCount: 2, + percentage: 50, + }, + { + dataset: 'logs-mysql.error-space2', + count: 1, + docsCount: 2, + percentage: 50, + }, + { + dataset: 'logs-nginx.access-default', + count: 0, + docsCount: 1, + percentage: 0, + }, + { + dataset: 'logs-nginx.access-space1', + count: 0, + docsCount: 1, + percentage: 0, + }, + { + dataset: 'logs-nginx.access-space2', + count: 0, + docsCount: 1, + percentage: 0, + }, + { + dataset: 'logs-nginx.error-default', + count: 1, + docsCount: 2, + percentage: 50, + }, + { + dataset: 'logs-nginx.error-space1', + count: 1, + docsCount: 2, + percentage: 50, + }, + { + dataset: 'logs-nginx.error-space2', + count: 1, + docsCount: 2, + percentage: 50, + }, + ], + }; + + expect(stats.body).to.eql(expected); + }); + + after(async () => { + await synthtrace.clean(); + }); + }); }); } + +const MORE_THAN_1024_CHARS = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?'; From 384ced6b34558d90c10c258517a94ffaaff64b51 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:51:35 +0200 Subject: [PATCH 084/123] skip failing test suite (#186440) --- .../pages/cis_integrations/cspm/cis_integration_gcp.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts index b75c4aeb2b7f35..121bf7cc2e5749 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts @@ -24,7 +24,8 @@ export default function (providerContext: FtrProviderContext) { const { getPageObjects } = providerContext; const pageObjects = getPageObjects(['cloudPostureDashboard', 'cisAddIntegration', 'header']); - describe('Test adding Cloud Security Posture Integrations CSPM GCP', function () { + // Failing: See https://github.com/elastic/kibana/issues/186440 + describe.skip('Test adding Cloud Security Posture Integrations CSPM GCP', function () { this.tags(['cloud_security_posture_cis_integration_cspm_gcp']); let cisIntegrationGcp: typeof pageObjects.cisAddIntegration.cisGcp; let cisIntegration: typeof pageObjects.cisAddIntegration; From e2b772aeaece0751aa85256a40be8d4c85128b51 Mon Sep 17 00:00:00 2001 From: Elena Stoeva <59341489+ElenaStoeva@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:35:24 +0100 Subject: [PATCH 085/123] [Rollups] Add deprecation warning callout (#186174) ## Summary This PR adds a deprecation warning callout to the Rollup list view and in the creation form.

Screenshots Screenshot 2024-06-13 at 12 16 03 Screenshot 2024-06-13 at 12 16 10
**How to test:** 1. Start Es and Kibana 2. Add the sample data "Sample web logs"
3. Elasticsearch only allows creating a rollup job if there is an existing rollup usage in the cluster. To simulate rollup usage, create a mock rollup index through Console: ``` PUT /mock_rollup_index { "mappings": { "_meta": { "_rollup": { "id": "logs_job", "index_pattern": "kibana_sample_data_logs", "rollup_index": "rollup_logstash", "cron": "* * * * * ?", "page_size": 1000, "groups": { "date_histogram": { "interval": "60m", "delay": "7d", "time_zone": "UTC", "field": "@timestamp" }, "terms": { "fields": [ "geo.src", "machine.os.keyword" ] }, "histogram": { "interval": "1003", "fields": [ "bytes", "memory" ] } }, "metrics": [ { "field": "bytes", "metrics": [ "avg" ] } ] } } } } ```
4. Create a sample rollup job through Console: ``` PUT _rollup/job/logs_job { "id": "logs_job", "index_pattern": "kibana_sample_data_logs", "rollup_index": "rollup_logstash", "cron": "* * * * * ?", "page_size": 1000, "groups": { "date_histogram": { "interval": "60m", "delay": "7d", "time_zone": "UTC", "field": "@timestamp" }, "terms": { "fields": [ "geo.src", "machine.os.keyword" ] }, "histogram": { "interval": "1003", "fields": [ "bytes", "memory" ] } }, "metrics": [ { "field": "bytes", "metrics": [ "avg" ] } ] } ```
5. Navigate to Stack Management -> Rollup Jobs 6. In the list view, verify that there is deprecation callout with the correct links (to the migration guide and the downsampling doc). 7. Start creating a new rollup job through the UI and verify that the deprecation callout exists on every step. ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- packages/kbn-doc-links/src/get_doc_links.ts | 1 + .../deprecation_callout.tsx | 50 +++++++++++++++++++ .../components/deprecation_callout/index.ts | 8 +++ .../crud_app/sections/components/index.js | 2 + .../sections/job_create/job_create.js | 5 ++ .../crud_app/sections/job_list/job_list.js | 5 ++ .../job_create_date_histogram.test.js | 4 ++ .../job_create_histogram.test.js | 4 ++ .../job_create_logistics.test.js | 4 ++ .../job_create_metrics.test.js | 4 ++ .../job_create_review.test.js | 4 ++ .../job_create_terms.test.js | 4 ++ .../test/client_integration/job_list.test.js | 4 ++ 13 files changed, 99 insertions(+) create mode 100644 x-pack/plugins/rollup/public/crud_app/sections/components/deprecation_callout/deprecation_callout.tsx create mode 100644 x-pack/plugins/rollup/public/crud_app/sections/components/deprecation_callout/index.ts diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 3fcd6df837c290..11e29fd14a35fe 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -435,6 +435,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D remoteClustersOnPremSetupTrustWithCert: `${ELASTICSEARCH_DOCS}remote-clusters-cert.html`, remoteClustersOnPremSetupTrustWithApiKey: `${ELASTICSEARCH_DOCS}remote-clusters-api-key.html`, remoteClustersCloudSetupTrust: `${ELASTIC_WEBSITE_URL}guide/en/cloud/current/ec-enable-ccs.html`, + rollupMigratingToDownsampling: `${ELASTICSEARCH_DOCS}rollup-migrating-to-downsampling.html`, rrf: `${ELASTICSEARCH_DOCS}rrf.html`, scriptParameters: `${ELASTICSEARCH_DOCS}modules-scripting-using.html#prefer-params`, secureCluster: `${ELASTICSEARCH_DOCS}secure-cluster.html`, diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/deprecation_callout/deprecation_callout.tsx b/x-pack/plugins/rollup/public/crud_app/sections/components/deprecation_callout/deprecation_callout.tsx new file mode 100644 index 00000000000000..4b36b9a086b69c --- /dev/null +++ b/x-pack/plugins/rollup/public/crud_app/sections/components/deprecation_callout/deprecation_callout.tsx @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiCallOut, EuiLink } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { documentationLinks } from '../../../services/documentation_links'; + +/* +A component for displaying a deprecation warning. + */ +export const DeprecationCallout = () => { + return ( + + + {i18n.translate('xpack.rollupJobs.deprecationCallout.migrationGuideLink', { + defaultMessage: 'migration guide', + })} + + ), + downsamplingLink: ( + + {i18n.translate('xpack.rollupJobs.deprecationCallout.downsamplingLink', { + defaultMessage: 'downsampling', + })} + + ), + }} + /> + + ); +}; diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/deprecation_callout/index.ts b/x-pack/plugins/rollup/public/crud_app/sections/components/deprecation_callout/index.ts new file mode 100644 index 00000000000000..cfa1379a950307 --- /dev/null +++ b/x-pack/plugins/rollup/public/crud_app/sections/components/deprecation_callout/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 { DeprecationCallout } from './deprecation_callout'; diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/index.js b/x-pack/plugins/rollup/public/crud_app/sections/components/index.js index ca2dbcfe23f9d6..9b1576902b7970 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/components/index.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/components/index.js @@ -21,3 +21,5 @@ export { } from './job_details'; export { JobStatus } from './job_status'; + +export { DeprecationCallout } from './deprecation_callout'; diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js index c782e8646b714e..4983fbb10ae8f2 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js @@ -13,6 +13,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { withKibana } from '@kbn/kibana-react-plugin/public'; +import { DeprecationCallout } from '../components'; import { EuiCallOut, @@ -556,6 +557,10 @@ export class JobCreateUi extends Component { + + + + {saveErrorFeedback} diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js index 04e88cd5848d29..7e03ade8b02219 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js @@ -26,6 +26,7 @@ import { documentationLinks } from '../../services/documentation_links'; import { JobTable } from './job_table'; import { DetailPanel } from './detail_panel'; +import { DeprecationCallout } from '../components'; import { DeprecatedPrompt } from './deprecated_prompt'; const REFRESH_RATE_MS = 30000; @@ -172,6 +173,10 @@ export class JobListUi extends Component { + + + + diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js index 022575e686679a..8804f53e65ac6c 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js @@ -63,6 +63,10 @@ describe('Create Rollup Job, step 2: Date histogram', () => { expect(exists('rollupJobCreateDateHistogramDocsButton')).toBe(true); }); + test('should have a deprecation callout', () => { + expect(exists('rollupDeprecationCallout')).toBe(true); + }); + it('should have the "next" and "back" button visible', () => { expect(exists('rollupJobBackButton')).toBe(true); expect(exists('rollupJobNextButton')).toBe(true); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js index bf2b76f75b9ab2..2ed942604842d2 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js @@ -70,6 +70,10 @@ describe('Create Rollup Job, step 4: Histogram', () => { expect(exists('rollupJobCreateHistogramDocsButton')).toBe(true); }); + test('should have a deprecation callout', () => { + expect(exists('rollupDeprecationCallout')).toBe(true); + }); + it('should have the "next" and "back" button visible', () => { expect(exists('rollupJobBackButton')).toBe(true); expect(exists('rollupJobNextButton')).toBe(true); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js index fdeccde8690a74..b073dc97b574a5 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js @@ -58,6 +58,10 @@ describe('Create Rollup Job, step 1: Logistics', () => { expect(exists('rollupJobCreateLogisticsDocsButton')).toBe(true); }); + test('should have a deprecation callout', () => { + expect(exists('rollupDeprecationCallout')).toBe(true); + }); + it('should only have the "next" button visible', () => { expect(exists('rollupJobBackButton')).toBe(false); expect(exists('rollupJobNextButton')).toBe(true); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js index 872e26727ba252..b63935b18240c8 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js @@ -71,6 +71,10 @@ describe('Create Rollup Job, step 5: Metrics', () => { expect(exists('rollupJobCreateMetricsDocsButton')).toBe(true); }); + test('should have a deprecation callout', () => { + expect(exists('rollupDeprecationCallout')).toBe(true); + }); + it('should have the "next" and "back" button visible', () => { expect(exists('rollupJobBackButton')).toBe(true); expect(exists('rollupJobNextButton')).toBe(true); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js index 5c0ceb7c25f74e..d1b42bfaafbcd0 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js @@ -70,6 +70,10 @@ describe('Create Rollup Job, step 6: Review', () => { expect(exists('rollupJobCreateReviewTitle')).toBe(true); }); + test('should have a deprecation callout', () => { + expect(exists('rollupDeprecationCallout')).toBe(true); + }); + it('should have the "next" and "save" button visible', () => { expect(exists('rollupJobBackButton')).toBe(true); expect(exists('rollupJobNextButton')).toBe(false); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js index 6736f82279c444..7b55e39ca08f90 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js @@ -68,6 +68,10 @@ describe('Create Rollup Job, step 3: Terms', () => { expect(exists('rollupJobCreateTermsDocsButton')).toBe(true); }); + test('should have a deprecation callout', () => { + expect(exists('rollupDeprecationCallout')).toBe(true); + }); + it('should have the "next" and "back" button visible', () => { expect(exists('rollupJobBackButton')).toBe(true); expect(exists('rollupJobNextButton')).toBe(true); diff --git a/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js index 553fc0712d6fcd..b329fce20c7bd3 100644 --- a/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js @@ -62,6 +62,10 @@ describe('', () => { startMock.http.get.mockClear(); }); + test('should have a deprecation callout', () => { + expect(exists('rollupDeprecationCallout')).toBe(true); + }); + test('should open the detail panel when clicking on a job in the table', () => { const { rows } = table.getMetaData('rollupJobsListTable'); const button = rows[0].columns[1].reactWrapper.find('button'); From 74c4d3a85ef1ef1edf22d15e6925ae1c88e2da6e Mon Sep 17 00:00:00 2001 From: Rodney Norris Date: Wed, 19 Jun 2024 05:47:18 -0500 Subject: [PATCH 086/123] [Search] Homepage Plugin setup (#186224) ## Summary Introducing the `search_homepage` plugin along with integration into `enterprise_search` and `serverless_search` behind a feature flag. This will allow implementing the feature gated behind the feature flag. To test these changes you can enable the feature flag with the Kibana Dev Console using the following command: ``` POST kbn:/internal/kibana/settings/searchHomepage:homepageEnabled {"value": true} ``` You can then disable the feature flag with the following command: ``` DELETE kbn:/internal/kibana/settings/searchHomepage:homepageEnabled ``` ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 1 + config/serverless.es.yml | 3 + docs/developer/plugin-list.asciidoc | 4 + package.json | 1 + packages/deeplinks/search/constants.ts | 1 + packages/deeplinks/search/deep_links.ts | 3 + packages/kbn-optimizer/limits.yml | 1 + .../test_suites/core_plugins/rendering.ts | 3 +- tsconfig.base.json | 2 + x-pack/.i18nrc.json | 1 + x-pack/plugins/enterprise_search/kibana.jsonc | 1 + .../__mocks__/kea_logic/kibana_logic.mock.ts | 2 + .../public/applications/index.tsx | 2 + .../components/layout/page_template.test.tsx | 28 +++++ .../components/layout/page_template.tsx | 37 ++++++ .../components/search_homepage.tsx | 35 ++++++ .../applications/search_homepage/index.tsx | 42 +++++++ .../search_homepage/jest.config.js | 26 +++++ .../shared/kibana/kibana_logic.ts | 7 ++ .../shared/kibana_chrome/breadcrumbs_home.ts | 18 +++ .../kibana_chrome/generate_breadcrumbs.ts | 7 +- .../public/applications/shared/layout/nav.tsx | 8 +- .../test_helpers/test_utils.test_helper.tsx | 6 +- .../public/navigation_tree.ts | 6 +- .../enterprise_search/public/plugin.ts | 107 +++++++++++++----- .../plugins/enterprise_search/tsconfig.json | 3 +- x-pack/plugins/search_homepage/README.mdx | 3 + .../plugins/search_homepage/common/index.ts | 14 +++ x-pack/plugins/search_homepage/jest.config.js | 15 +++ x-pack/plugins/search_homepage/kibana.jsonc | 26 +++++ .../search_homepage/public/application.tsx | 37 ++++++ .../public/components/search_homepage.tsx | 32 ++++++ .../components/search_homepage_body.tsx | 24 ++++ .../components/search_homepage_header.tsx | 26 +++++ .../public/components/stack_app.tsx | 19 ++++ .../search_homepage/public/embeddable.tsx | 12 ++ .../search_homepage/public/feature_flags.ts | 13 +++ .../public/hooks/use_kibana.ts | 11 ++ .../plugins/search_homepage/public/index.ts | 20 ++++ .../plugins/search_homepage/public/plugin.ts | 80 +++++++++++++ .../plugins/search_homepage/public/router.tsx | 19 ++++ .../plugins/search_homepage/public/types.ts | 74 ++++++++++++ .../plugins/search_homepage/server/config.ts | 27 +++++ .../plugins/search_homepage/server/index.ts | 17 +++ .../plugins/search_homepage/server/plugin.ts | 28 +++++ .../plugins/search_homepage/server/types.ts | 11 ++ x-pack/plugins/search_homepage/tsconfig.json | 30 +++++ x-pack/plugins/serverless_search/kibana.jsonc | 1 + .../public/navigation_tree.ts | 6 +- .../serverless_search/public/plugin.ts | 31 ++++- .../plugins/serverless_search/public/types.ts | 24 ++-- .../plugins/serverless_search/tsconfig.json | 1 + .../functional/page_objects/index.ts | 2 + .../page_objects/svl_search_homepage.ts | 26 +++++ .../functional/services/index.ts | 2 + .../functional/services/ui_settings.ts | 32 ++++++ .../functional/test_suites/search/index.ts | 1 + .../test_suites/search/search_homepage.ts | 58 ++++++++++ yarn.lock | 4 + 59 files changed, 1025 insertions(+), 56 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/search_homepage/components/search_homepage.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/search_homepage/index.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/search_homepage/jest.config.js create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/breadcrumbs_home.ts create mode 100644 x-pack/plugins/search_homepage/README.mdx create mode 100644 x-pack/plugins/search_homepage/common/index.ts create mode 100644 x-pack/plugins/search_homepage/jest.config.js create mode 100644 x-pack/plugins/search_homepage/kibana.jsonc create mode 100644 x-pack/plugins/search_homepage/public/application.tsx create mode 100644 x-pack/plugins/search_homepage/public/components/search_homepage.tsx create mode 100644 x-pack/plugins/search_homepage/public/components/search_homepage_body.tsx create mode 100644 x-pack/plugins/search_homepage/public/components/search_homepage_header.tsx create mode 100644 x-pack/plugins/search_homepage/public/components/stack_app.tsx create mode 100644 x-pack/plugins/search_homepage/public/embeddable.tsx create mode 100644 x-pack/plugins/search_homepage/public/feature_flags.ts create mode 100644 x-pack/plugins/search_homepage/public/hooks/use_kibana.ts create mode 100644 x-pack/plugins/search_homepage/public/index.ts create mode 100644 x-pack/plugins/search_homepage/public/plugin.ts create mode 100644 x-pack/plugins/search_homepage/public/router.tsx create mode 100644 x-pack/plugins/search_homepage/public/types.ts create mode 100644 x-pack/plugins/search_homepage/server/config.ts create mode 100644 x-pack/plugins/search_homepage/server/index.ts create mode 100644 x-pack/plugins/search_homepage/server/plugin.ts create mode 100644 x-pack/plugins/search_homepage/server/types.ts create mode 100644 x-pack/plugins/search_homepage/tsconfig.json create mode 100644 x-pack/test_serverless/functional/page_objects/svl_search_homepage.ts create mode 100644 x-pack/test_serverless/functional/services/ui_settings.ts create mode 100644 x-pack/test_serverless/functional/test_suites/search/search_homepage.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 690698e02a1421..e06b53da0ab57e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -716,6 +716,7 @@ packages/kbn-search-connectors @elastic/search-kibana x-pack/plugins/search_connectors @elastic/search-kibana packages/kbn-search-errors @elastic/kibana-data-discovery examples/search_examples @elastic/kibana-data-discovery +x-pack/plugins/search_homepage @elastic/search-kibana packages/kbn-search-index-documents @elastic/search-kibana x-pack/plugins/search_inference_endpoints @elastic/search-kibana x-pack/plugins/search_notebooks @elastic/search-kibana diff --git a/config/serverless.es.yml b/config/serverless.es.yml index 531fa5520c0aee..a170cf569b54df 100644 --- a/config/serverless.es.yml +++ b/config/serverless.es.yml @@ -69,3 +69,6 @@ xpack.searchInferenceEndpoints.ui.enabled: false # Search Notebooks xpack.search.notebooks.catalog.url: https://elastic-enterprise-search.s3.us-east-2.amazonaws.com/serverless/catalog.json + +# Search Homepage +xpack.search.homepage.ui.enabled: true diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index f78070b9bfa49b..fc15206bd284d2 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -789,6 +789,10 @@ It uses Chromium and Puppeteer underneath to run the browser in headless mode. |This plugin contains common assets and endpoints for the use of connectors in Kibana. Primarily used by the enterprise_search and serverless_search plugins. +|{kib-repo}blob/{branch}/x-pack/plugins/search_homepage/README.mdx[searchHomepage] +|The Search Homepage is a shared homepage for elasticsearch users. + + |{kib-repo}blob/{branch}/x-pack/plugins/search_inference_endpoints/README.md[searchInferenceEndpoints] |The Inference Endpoints is a tool used to manage inference endpoints diff --git a/package.json b/package.json index 48abd4ddd30b7c..efd020e91df662 100644 --- a/package.json +++ b/package.json @@ -727,6 +727,7 @@ "@kbn/search-connectors-plugin": "link:x-pack/plugins/search_connectors", "@kbn/search-errors": "link:packages/kbn-search-errors", "@kbn/search-examples-plugin": "link:examples/search_examples", + "@kbn/search-homepage": "link:x-pack/plugins/search_homepage", "@kbn/search-index-documents": "link:packages/kbn-search-index-documents", "@kbn/search-inference-endpoints": "link:x-pack/plugins/search_inference_endpoints", "@kbn/search-notebooks": "link:x-pack/plugins/search_notebooks", diff --git a/packages/deeplinks/search/constants.ts b/packages/deeplinks/search/constants.ts index 36d31d22dfe21d..3fdcc78bb68a17 100644 --- a/packages/deeplinks/search/constants.ts +++ b/packages/deeplinks/search/constants.ts @@ -17,3 +17,4 @@ export const SERVERLESS_ES_APP_ID = 'serverlessElasticsearch'; export const SERVERLESS_ES_CONNECTORS_ID = 'serverlessConnectors'; export const SERVERLESS_ES_SEARCH_PLAYGROUND_ID = 'searchPlayground'; export const SERVERLESS_ES_SEARCH_INFERENCE_ENDPOINTS_ID = 'searchInferenceEndpoints'; +export const SEARCH_HOMEPAGE = 'searchHomepage'; diff --git a/packages/deeplinks/search/deep_links.ts b/packages/deeplinks/search/deep_links.ts index 8eeceff8f8ca21..f004d1b2c9dd6a 100644 --- a/packages/deeplinks/search/deep_links.ts +++ b/packages/deeplinks/search/deep_links.ts @@ -17,6 +17,7 @@ import { ENTERPRISE_SEARCH_WORKPLACESEARCH_APP_ID, SERVERLESS_ES_SEARCH_PLAYGROUND_ID, SERVERLESS_ES_SEARCH_INFERENCE_ENDPOINTS_ID, + SEARCH_HOMEPAGE, } from './constants'; export type EnterpriseSearchApp = typeof ENTERPRISE_SEARCH_APP_ID; @@ -29,6 +30,7 @@ export type ServerlessSearchApp = typeof SERVERLESS_ES_APP_ID; export type ConnectorsId = typeof SERVERLESS_ES_CONNECTORS_ID; export type SearchPlaygroundId = typeof SERVERLESS_ES_SEARCH_PLAYGROUND_ID; export type SearchInferenceEndpointsId = typeof SERVERLESS_ES_SEARCH_INFERENCE_ENDPOINTS_ID; +export type SearchHomepage = typeof SEARCH_HOMEPAGE; export type ContentLinkId = 'searchIndices' | 'connectors' | 'webCrawlers'; @@ -47,6 +49,7 @@ export type DeepLinkId = | ConnectorsId | SearchPlaygroundId | SearchInferenceEndpointsId + | SearchHomepage | `${EnterpriseSearchContentApp}:${ContentLinkId}` | `${EnterpriseSearchApplicationsApp}:${ApplicationsLinkId}` | `${EnterpriseSearchAppsearchApp}:${AppsearchLinkId}`; diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 336cfd2c6b93db..c3ffc507387b8a 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -132,6 +132,7 @@ pageLoadAssetSize: screenshotMode: 17856 screenshotting: 22870 searchConnectors: 30000 + searchHomepage: 19831 searchInferenceEndpoints: 20470 searchNotebooks: 18942 searchPlayground: 19325 diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 31e0a44b9e823e..19eeef57ba62b9 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -313,8 +313,9 @@ export default function ({ getService }: PluginFunctionalProviderContext) { // 'xpack.reporting.poll.jobsRefresh.intervalErrorMultiplier (number)', 'xpack.rollup.ui.enabled (boolean)', 'xpack.saved_object_tagging.cache_refresh_interval (duration)', - 'xpack.searchPlayground.ui.enabled (boolean)', + 'xpack.search.homepage.ui.enabled (boolean)', 'xpack.searchInferenceEndpoints.ui.enabled (boolean)', + 'xpack.searchPlayground.ui.enabled (boolean)', 'xpack.security.loginAssistanceMessage (string)', 'xpack.security.sameSiteCookies (alternatives)', 'xpack.security.showInsecureClusterWarning (boolean)', diff --git a/tsconfig.base.json b/tsconfig.base.json index ea18fe456af854..0f8d9a11563e05 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1426,6 +1426,8 @@ "@kbn/search-errors/*": ["packages/kbn-search-errors/*"], "@kbn/search-examples-plugin": ["examples/search_examples"], "@kbn/search-examples-plugin/*": ["examples/search_examples/*"], + "@kbn/search-homepage": ["x-pack/plugins/search_homepage"], + "@kbn/search-homepage/*": ["x-pack/plugins/search_homepage/*"], "@kbn/search-index-documents": ["packages/kbn-search-index-documents"], "@kbn/search-index-documents/*": ["packages/kbn-search-index-documents/*"], "@kbn/search-inference-endpoints": ["x-pack/plugins/search_inference_endpoints"], diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 2943af3cf46d54..1f224ca164e526 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -92,6 +92,7 @@ "xpack.rollupJobs": ["plugins/rollup"], "xpack.runtimeFields": "plugins/runtime_fields", "xpack.screenshotting": "plugins/screenshotting", + "xpack.searchHomepage": "plugins/search_homepage", "xpack.searchNotebooks": "plugins/search_notebooks", "xpack.searchPlayground": "plugins/search_playground", "xpack.searchInferenceEndpoints": "plugins/search_inference_endpoints", diff --git a/x-pack/plugins/enterprise_search/kibana.jsonc b/x-pack/plugins/enterprise_search/kibana.jsonc index 3855fd3d9e1f9c..0dc2562ff2fe39 100644 --- a/x-pack/plugins/enterprise_search/kibana.jsonc +++ b/x-pack/plugins/enterprise_search/kibana.jsonc @@ -30,6 +30,7 @@ "guidedOnboarding", "console", "searchConnectors", + "searchHomepage", "searchPlayground", "searchInferenceEndpoints", "embeddable", diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts index cca5523ded6814..5f4774be15b960 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts @@ -45,6 +45,7 @@ export const mockKibanaValues = { history: mockHistory, indexMappingComponent: null, isCloud: false, + isSearchHomepageEnabled: false, isSidebarEnabled: true, lens: { EmbeddableComponent: jest.fn(), @@ -64,6 +65,7 @@ export const mockKibanaValues = { hasWebCrawler: true, }, renderHeaderActions: jest.fn(), + searchHomepage: null, searchInferenceEndpoints: null, searchPlayground: searchPlaygroundMock.createStart(), security: securityMock.createStart(), diff --git a/x-pack/plugins/enterprise_search/public/applications/index.tsx b/x-pack/plugins/enterprise_search/public/applications/index.tsx index ea45e121470e22..98d6677c35fc1c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/index.tsx @@ -117,6 +117,7 @@ export const renderApp = ( guidedOnboarding, history, indexMappingComponent, + isSearchHomepageEnabled: plugins.searchHomepage?.isHomepageFeatureEnabled() ?? false, isSidebarEnabled, lens, ml, @@ -127,6 +128,7 @@ export const renderApp = ( params.setHeaderActionMenu( HeaderActions ? renderHeaderActions.bind(null, HeaderActions, store, params) : undefined ), + searchHomepage: plugins.searchHomepage, searchPlayground: plugins.searchPlayground, searchInferenceEndpoints: plugins.searchInferenceEndpoints, security, diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.test.tsx b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.test.tsx new file mode 100644 index 00000000000000..c44cc39c5eb1de --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.test.tsx @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { TestHelper } from '../../../test_helpers/test_utils.test_helper'; + +import { SearchHomepagePageTemplate } from './page_template'; + +describe('SearchHomepagePageTemplate', () => { + beforeAll(() => { + TestHelper.prepare(); + }); + + it('renders as expected', async () => { + const { container } = TestHelper.render( + +
Test
+
+ ); + + expect(container.querySelector('.kbnSolutionNav__title')).toHaveTextContent('Search'); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.tsx new file mode 100644 index 00000000000000..76f2e6e526239a --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.tsx @@ -0,0 +1,37 @@ +/* + * 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 { SEARCH_PRODUCT_NAME } from '../../../../../common/constants'; +import { SetSearchChrome } from '../../../shared/kibana_chrome'; +import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout'; +import { useEnterpriseSearchNav } from '../../../shared/layout'; +import { SendEnterpriseSearchTelemetry } from '../../../shared/telemetry'; + +export const SearchHomepagePageTemplate: React.FC = ({ + children, + pageChrome, + pageViewTelemetry, + ...pageTemplateProps +}) => { + return ( + } + > + {pageViewTelemetry && ( + + )} + {children} + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/search_homepage.tsx b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/search_homepage.tsx new file mode 100644 index 00000000000000..a605010fcb00d1 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/search_homepage.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useValues } from 'kea'; + +import { KibanaLogic } from '../../shared/kibana'; +import { SetSearchChrome } from '../../shared/kibana_chrome'; + +import { SearchHomepagePageTemplate } from './layout/page_template'; + +export const SearchHomepagePage = () => { + const { isSearchHomepageEnabled, searchHomepage } = useValues(KibanaLogic); + + if (!isSearchHomepageEnabled || !searchHomepage) { + return null; + } + + return ( + + + + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/index.tsx b/x-pack/plugins/enterprise_search/public/applications/search_homepage/index.tsx new file mode 100644 index 00000000000000..43963f21d3b5da --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/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 { Routes, Route } from '@kbn/shared-ux-router'; + +import { isVersionMismatch } from '../../../common/is_version_mismatch'; +import type { InitialAppData } from '../../../common/types'; +import { VersionMismatchPage } from '../shared/version_mismatch'; + +import { SearchHomepagePage } from './components/search_homepage'; + +export const SearchHomepage: React.FC = (props) => { + const { enterpriseSearchVersion, kibanaVersion } = props; + const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); + + const showView = () => { + if (incompatibleVersions) { + return ( + + ); + } + + return ; + }; + + return ( + + + {showView()} + + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/jest.config.js b/x-pack/plugins/enterprise_search/public/applications/search_homepage/jest.config.js new file mode 100644 index 00000000000000..c18a3561afb657 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/jest.config.js @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../../..', + roots: ['/x-pack/plugins/enterprise_search/public/applications/search_homepage'], + collectCoverage: true, + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/plugins/enterprise_search/public/applications/**/*.{ts,tsx}', + '!/x-pack/plugins/enterprise_search/public/*.ts', + '!/x-pack/plugins/enterprise_search/server/*.ts', + '!/x-pack/plugins/enterprise_search/public/applications/test_helpers/**/*.{ts,tsx}', + ], + coverageDirectory: + '/target/kibana-coverage/jest/x-pack/plugins/enterprise_search/public/applications/search_homepage', + modulePathIgnorePatterns: [ + '/x-pack/plugins/enterprise_search/public/applications/app_search/cypress', + '/x-pack/plugins/enterprise_search/public/applications/workplace_search/cypress', + ], +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts index da18e9e8bb44f1..4920b25cffd75a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts @@ -29,6 +29,7 @@ import { LensPublicStart } from '@kbn/lens-plugin/public'; import { MlPluginStart } from '@kbn/ml-plugin/public'; import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants'; import { ConnectorDefinition } from '@kbn/search-connectors-plugin/public'; +import type { SearchHomepagePluginStart } from '@kbn/search-homepage/public'; import { SearchInferenceEndpointsPluginStart } from '@kbn/search-inference-endpoints/public'; import { SearchPlaygroundPluginStart } from '@kbn/search-playground/public'; import { AuthenticatedUser, SecurityPluginStart } from '@kbn/security-plugin/public'; @@ -58,6 +59,7 @@ export interface KibanaLogicProps { guidedOnboarding?: GuidedOnboardingPluginStart; history: ScopedHistory; indexMappingComponent?: React.FC; + isSearchHomepageEnabled: boolean; isSidebarEnabled: boolean; lens?: LensPublicStart; ml?: MlPluginStart; @@ -65,6 +67,7 @@ export interface KibanaLogicProps { productAccess: ProductAccess; productFeatures: ProductFeatures; renderHeaderActions(HeaderActions?: FC): void; + searchHomepage?: SearchHomepagePluginStart; searchPlayground?: SearchPlaygroundPluginStart; searchInferenceEndpoints?: SearchInferenceEndpointsPluginStart; security?: SecurityPluginStart; @@ -91,6 +94,7 @@ export interface KibanaValues { history: ScopedHistory; indexMappingComponent: React.FC | null; isCloud: boolean; + isSearchHomepageEnabled: boolean; isSidebarEnabled: boolean; lens: LensPublicStart | null; ml: MlPluginStart | null; @@ -98,6 +102,7 @@ export interface KibanaValues { productAccess: ProductAccess; productFeatures: ProductFeatures; renderHeaderActions(HeaderActions?: FC): void; + searchHomepage: SearchHomepagePluginStart | null; searchPlayground: SearchPlaygroundPluginStart | null; searchInferenceEndpoints: SearchInferenceEndpointsPluginStart | null; security: SecurityPluginStart | null; @@ -129,6 +134,7 @@ export const KibanaLogic = kea>({ guidedOnboarding: [props.guidedOnboarding || null, {}], history: [props.history, {}], indexMappingComponent: [props.indexMappingComponent || null, {}], + isSearchHomepageEnabled: [props.isSearchHomepageEnabled, {}], isSidebarEnabled: [props.isSidebarEnabled, {}], lens: [props.lens || null, {}], ml: [props.ml || null, {}], @@ -143,6 +149,7 @@ export const KibanaLogic = kea>({ productAccess: [props.productAccess, {}], productFeatures: [props.productFeatures, {}], renderHeaderActions: [props.renderHeaderActions, {}], + searchHomepage: [props.searchHomepage || null, {}], searchPlayground: [props.searchPlayground || null, {}], searchInferenceEndpoints: [props.searchInferenceEndpoints || null, {}], security: [props.security || null, {}], diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/breadcrumbs_home.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/breadcrumbs_home.ts new file mode 100644 index 00000000000000..34e9e12c88b761 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/breadcrumbs_home.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 { ENTERPRISE_SEARCH_OVERVIEW_PLUGIN } from '../../../../common/constants'; + +/** + * HACK for base homepage URL, this can be removed and updated to a static + * URL when Search Homepage is no longer feature flagged. + */ +const breadCrumbHome = { url: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL }; +export const getHomeURL = () => breadCrumbHome.url; +export const setBreadcrumbHomeUrl = (url: string) => { + breadCrumbHome.url = url; +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts index ac3e6d7a6437d6..5798a48680d1f6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts @@ -15,7 +15,6 @@ import { APP_SEARCH_PLUGIN, ENTERPRISE_SEARCH_CONTENT_PLUGIN, INFERENCE_ENDPOINTS_PLUGIN, - ENTERPRISE_SEARCH_OVERVIEW_PLUGIN, ENTERPRISE_SEARCH_PRODUCT_NAME, AI_SEARCH_PLUGIN, SEARCH_EXPERIENCES_PLUGIN, @@ -29,6 +28,8 @@ import { HttpLogic } from '../http'; import { KibanaLogic } from '../kibana'; import { letBrowserHandleEvent, createHref } from '../react_router_helpers'; +import { getHomeURL } from './breadcrumbs_home'; + /** * Types */ @@ -107,7 +108,7 @@ export const useSearchBreadcrumbs = (breadcrumbs: Breadcrumbs = []) => useEuiBreadcrumbs([ { text: SEARCH_PRODUCT_NAME, - path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, + path: getHomeURL(), shouldNotCreateHref: true, }, ...breadcrumbs, @@ -117,7 +118,7 @@ export const useEnterpriseSearchBreadcrumbs = (breadcrumbs: Breadcrumbs = []) => useEuiBreadcrumbs([ { text: ENTERPRISE_SEARCH_PRODUCT_NAME, - path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, + path: getHomeURL(), shouldNotCreateHref: true, }, ...breadcrumbs, diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx index bd53ed235d4cb9..77454581c61e77 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx @@ -49,7 +49,8 @@ import { generateNavLink } from './nav_link_helpers'; * @returns The Enterprise Search navigation items */ export const useEnterpriseSearchNav = (alwaysReturn = false) => { - const { isSidebarEnabled, productAccess } = useValues(KibanaLogic); + const { isSearchHomepageEnabled, searchHomepage, isSidebarEnabled, productAccess } = + useValues(KibanaLogic); const indicesNavItems = useIndicesNav(); if (!isSidebarEnabled && !alwaysReturn) return undefined; @@ -66,7 +67,10 @@ export const useEnterpriseSearchNav = (alwaysReturn = false) => { ...generateNavLink({ shouldNotCreateHref: true, shouldShowActiveForSubroutes: true, - to: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, + to: + isSearchHomepageEnabled && searchHomepage + ? searchHomepage.app.appRoute + : ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, }), }, { diff --git a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx index 5601c006a44330..0050165b8be502 100644 --- a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx @@ -62,6 +62,7 @@ export const mockKibanaProps: KibanaLogicProps = { indexMappingComponent: () => { return <>; }, + isSearchHomepageEnabled: false, isSidebarEnabled: true, lens: { EmbeddableComponent: jest.fn(), @@ -84,6 +85,7 @@ export const mockKibanaProps: KibanaLogicProps = { hasWebCrawler: true, }, renderHeaderActions: jest.fn(), + searchHomepage: undefined, searchPlayground: searchPlaygroundMock.createStart(), security: securityMock.createStart(), setBreadcrumbs: jest.fn(), @@ -114,7 +116,7 @@ interface TestHelper { defaultMockValues: typeof DEFAULT_VALUES; mountLogic: (logicFile: LogicFile, props?: object) => void; prepare: (options?: PrepareOptions) => void; - render: (children: JSX.Element) => void; + render: (children: JSX.Element) => ReturnType; } export const TestHelper: TestHelper = { @@ -147,7 +149,7 @@ export const TestHelper: TestHelper = { TestHelper.actionsToRun.forEach((action) => { action(); }); - testingLibraryRender( + return testingLibraryRender( {children} diff --git a/x-pack/plugins/enterprise_search/public/navigation_tree.ts b/x-pack/plugins/enterprise_search/public/navigation_tree.ts index dc079aec906889..051cfaa6779af5 100644 --- a/x-pack/plugins/enterprise_search/public/navigation_tree.ts +++ b/x-pack/plugins/enterprise_search/public/navigation_tree.ts @@ -67,12 +67,14 @@ const euiItemTypeToNodeDefinition = ({ export const getNavigationTreeDefinition = ({ dynamicItems$, + isSearchHomepageEnabled, }: { dynamicItems$: Observable; + isSearchHomepageEnabled: boolean; }): AddSolutionNavigationArg => { return { dataTestSubj: 'searchSideNav', - homePage: 'enterpriseSearch', + homePage: isSearchHomepageEnabled ? 'searchHomepage' : 'enterpriseSearch', icon, id: 'es', navigationTree$: dynamicItems$.pipe( @@ -84,7 +86,7 @@ export const getNavigationTreeDefinition = ({ breadcrumbStatus: 'hidden', children: [ { - link: 'enterpriseSearch', + link: isSearchHomepageEnabled ? 'searchHomepage' : 'enterpriseSearch', }, { getIsActive: ({ pathNameSerialized, prepend }) => { diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index 9c03fb623fa3dd..280de2f04356b4 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -32,6 +32,10 @@ import { MlPluginStart } from '@kbn/ml-plugin/public'; import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants'; import { SearchConnectorsPluginStart } from '@kbn/search-connectors-plugin/public'; +import type { + SearchHomepagePluginSetup, + SearchHomepagePluginStart, +} from '@kbn/search-homepage/public'; import { SearchInferenceEndpointsPluginStart } from '@kbn/search-inference-endpoints/public'; import { SearchPlaygroundPluginStart } from '@kbn/search-playground/public'; import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public'; @@ -67,6 +71,7 @@ import { import { INFERENCE_ENDPOINTS_PATH } from './applications/enterprise_search_relevance/routes'; import { docLinks } from './applications/shared/doc_links'; +import { setBreadcrumbHomeUrl } from './applications/shared/kibana_chrome/breadcrumbs_home'; import type { DynamicSideNavItems } from './navigation_tree'; export interface ClientData extends InitialAppData { @@ -80,6 +85,7 @@ export type EnterpriseSearchPublicStart = ReturnType { - const kibanaDeps = await this.getKibanaDeps(core, params, cloud); - const { chrome, http } = kibanaDeps.core; - chrome.docTitle.change(ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAME); + if (useSearchHomepage) { + const { app } = plugins.searchHomepage!; + core.application.register({ + ...app, + category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, + visibleIn: ['home', 'kibanaOverview', 'globalSearch', 'sideNav'], + mount: async (params: AppMountParameters) => { + const kibanaDeps = await this.getKibanaDeps(core, params, cloud); + const { chrome, http } = kibanaDeps.core; + chrome.docTitle.change(app.title); - await this.getInitialData(http); - const pluginData = this.getPluginData(); + await this.getInitialData(http); + const pluginData = this.getPluginData(); - const { renderApp } = await import('./applications'); - const { EnterpriseSearchOverview } = await import( - './applications/enterprise_search_overview' - ); + const { renderApp } = await import('./applications'); + const { SearchHomepage } = await import('./applications/search_homepage'); - return renderApp(EnterpriseSearchOverview, kibanaDeps, pluginData); - }, - title: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAV_TITLE, - visibleIn: ['home', 'kibanaOverview', 'globalSearch', 'sideNav'], - }); + return renderApp(SearchHomepage, kibanaDeps, pluginData); + }, + }); + setBreadcrumbHomeUrl(app.appRoute); + } else { + core.application.register({ + appRoute: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, + category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, + id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID, + mount: async (params: AppMountParameters) => { + const kibanaDeps = await this.getKibanaDeps(core, params, cloud); + const { chrome, http } = kibanaDeps.core; + chrome.docTitle.change(ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAME); + + await this.getInitialData(http); + const pluginData = this.getPluginData(); + + const { renderApp } = await import('./applications'); + const { EnterpriseSearchOverview } = await import( + './applications/enterprise_search_overview' + ); + + return renderApp(EnterpriseSearchOverview, kibanaDeps, pluginData); + }, + title: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAV_TITLE, + visibleIn: ['home', 'kibanaOverview', 'globalSearch', 'sideNav'], + }); + } core.application.register({ appRoute: ENTERPRISE_SEARCH_CONTENT_PLUGIN.URL, @@ -512,14 +545,27 @@ export class EnterpriseSearchPlugin implements Plugin { } if (plugins.home) { - plugins.home.featureCatalogue.registerSolution({ - description: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.DESCRIPTION, - icon: 'logoEnterpriseSearch', - id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID, - order: 100, - path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, - title: SEARCH_PRODUCT_NAME, - }); + if (useSearchHomepage) { + const { searchHomepage } = plugins; + + plugins.home.featureCatalogue.registerSolution({ + description: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.DESCRIPTION, + icon: 'logoEnterpriseSearch', + id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID, + order: 100, + path: searchHomepage!.app.appRoute, + title: SEARCH_PRODUCT_NAME, + }); + } else { + plugins.home.featureCatalogue.registerSolution({ + description: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.DESCRIPTION, + icon: 'logoEnterpriseSearch', + id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID, + order: 100, + path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, + title: SEARCH_PRODUCT_NAME, + }); + } plugins.home.featureCatalogue.register({ category: 'data', @@ -587,7 +633,10 @@ export class EnterpriseSearchPlugin implements Plugin { import('./navigation_tree').then(({ getNavigationTreeDefinition }) => { return plugins.navigation.addSolutionNavigation( - getNavigationTreeDefinition({ dynamicItems$: this.sideNavDynamicItems$ }) + getNavigationTreeDefinition({ + dynamicItems$: this.sideNavDynamicItems$, + isSearchHomepageEnabled: plugins.searchHomepage?.isHomepageFeatureEnabled() ?? false, + }) ); }); diff --git a/x-pack/plugins/enterprise_search/tsconfig.json b/x-pack/plugins/enterprise_search/tsconfig.json index 3a66b8350be4fe..a6bb797de5eb13 100644 --- a/x-pack/plugins/enterprise_search/tsconfig.json +++ b/x-pack/plugins/enterprise_search/tsconfig.json @@ -79,6 +79,7 @@ "@kbn/cloud", "@kbn/try-in-console", "@kbn/core-chrome-browser", - "@kbn/navigation-plugin" + "@kbn/navigation-plugin", + "@kbn/search-homepage" ] } diff --git a/x-pack/plugins/search_homepage/README.mdx b/x-pack/plugins/search_homepage/README.mdx new file mode 100644 index 00000000000000..00ba4f491c6077 --- /dev/null +++ b/x-pack/plugins/search_homepage/README.mdx @@ -0,0 +1,3 @@ +# Search Homepage + +The Search Homepage is a shared homepage for elasticsearch users. diff --git a/x-pack/plugins/search_homepage/common/index.ts b/x-pack/plugins/search_homepage/common/index.ts new file mode 100644 index 00000000000000..d93d5c49f8cc54 --- /dev/null +++ b/x-pack/plugins/search_homepage/common/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const PLUGIN_ID = 'searchHomepage'; +export const PLUGIN_NAME = 'searchHomepage'; + +/** + * UI Setting id for the Search Homepage feature flag + */ +export const HOMEPAGE_FEATURE_FLAG_ID = 'searchHomepage:homepageEnabled'; diff --git a/x-pack/plugins/search_homepage/jest.config.js b/x-pack/plugins/search_homepage/jest.config.js new file mode 100644 index 00000000000000..65cd8f1e34252a --- /dev/null +++ b/x-pack/plugins/search_homepage/jest.config.js @@ -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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/x-pack/plugins/search_homepage'], + coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/search_homepage', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/x-pack/plugins/search_homepage/{public,server}/**/*.{ts,tsx}'], +}; diff --git a/x-pack/plugins/search_homepage/kibana.jsonc b/x-pack/plugins/search_homepage/kibana.jsonc new file mode 100644 index 00000000000000..0e345ab0d330a7 --- /dev/null +++ b/x-pack/plugins/search_homepage/kibana.jsonc @@ -0,0 +1,26 @@ +{ + "type": "plugin", + "id": "@kbn/search-homepage", + "owner": "@elastic/search-kibana", + "plugin": { + "id": "searchHomepage", + "server": true, + "browser": true, + "configPath": [ + "xpack", + "search", + "homepage" + ], + "requiredPlugins": [ + "share", + ], + "optionalPlugins": [ + "cloud", + "console", + "usageCollection", + ], + "requiredBundles": [ + "kibanaReact" + ] + } +} diff --git a/x-pack/plugins/search_homepage/public/application.tsx b/x-pack/plugins/search_homepage/public/application.tsx new file mode 100644 index 00000000000000..4af256de498ed3 --- /dev/null +++ b/x-pack/plugins/search_homepage/public/application.tsx @@ -0,0 +1,37 @@ +/* + * 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 ReactDOM from 'react-dom'; +import { CoreStart } from '@kbn/core/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { I18nProvider } from '@kbn/i18n-react'; +import { Router } from '@kbn/shared-ux-router'; +import { SearchHomepageAppPluginStartDependencies } from './types'; +import { HomepageRouter } from './router'; + +export const renderApp = async ( + core: CoreStart, + services: SearchHomepageAppPluginStartDependencies, + element: HTMLElement +) => { + ReactDOM.render( + + + + + + + + + , + element + ); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/x-pack/plugins/search_homepage/public/components/search_homepage.tsx b/x-pack/plugins/search_homepage/public/components/search_homepage.tsx new file mode 100644 index 00000000000000..7af02cbcf3275d --- /dev/null +++ b/x-pack/plugins/search_homepage/public/components/search_homepage.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { EuiPageTemplate } from '@elastic/eui'; + +import { useKibana } from '../hooks/use_kibana'; +import { SearchHomepageBody } from './search_homepage_body'; +import { SearchHomepageHeader } from './search_homepage_header'; + +export const SearchHomepagePage = () => { + const { + services: { console: consolePlugin }, + } = useKibana(); + + const embeddableConsole = useMemo( + () => (consolePlugin?.EmbeddableConsole ? : null), + [consolePlugin] + ); + + return ( + + + + {embeddableConsole} + + ); +}; diff --git a/x-pack/plugins/search_homepage/public/components/search_homepage_body.tsx b/x-pack/plugins/search_homepage/public/components/search_homepage_body.tsx new file mode 100644 index 00000000000000..808393594e7d8c --- /dev/null +++ b/x-pack/plugins/search_homepage/public/components/search_homepage_body.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; + +export const SearchHomepageBody = () => ( + +
+ +); diff --git a/x-pack/plugins/search_homepage/public/components/search_homepage_header.tsx b/x-pack/plugins/search_homepage/public/components/search_homepage_header.tsx new file mode 100644 index 00000000000000..941655d67cdabb --- /dev/null +++ b/x-pack/plugins/search_homepage/public/components/search_homepage_header.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiPageTemplate, EuiTitle } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +export const SearchHomepageHeader = () => ( + +

+ +

+ + } + data-test-subj="search-homepage-header" + rightSideItems={[]} + /> +); diff --git a/x-pack/plugins/search_homepage/public/components/stack_app.tsx b/x-pack/plugins/search_homepage/public/components/stack_app.tsx new file mode 100644 index 00000000000000..ca18ac7112c091 --- /dev/null +++ b/x-pack/plugins/search_homepage/public/components/stack_app.tsx @@ -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 React from 'react'; +import { SearchHomepageBody } from './search_homepage_body'; +import { SearchHomepageHeader } from './search_homepage_header'; + +export const App: React.FC = () => { + return ( + <> + + + + ); +}; diff --git a/x-pack/plugins/search_homepage/public/embeddable.tsx b/x-pack/plugins/search_homepage/public/embeddable.tsx new file mode 100644 index 00000000000000..ee69062ea3fe56 --- /dev/null +++ b/x-pack/plugins/search_homepage/public/embeddable.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { dynamic } from '@kbn/shared-ux-utility'; + +export const SearchHomepage = dynamic(async () => ({ + default: (await import('./components/stack_app')).App, +})); diff --git a/x-pack/plugins/search_homepage/public/feature_flags.ts b/x-pack/plugins/search_homepage/public/feature_flags.ts new file mode 100644 index 00000000000000..bea65a8e1548f2 --- /dev/null +++ b/x-pack/plugins/search_homepage/public/feature_flags.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IUiSettingsClient } from '@kbn/core/public'; +import { HOMEPAGE_FEATURE_FLAG_ID } from '../common'; + +export function isHomepageEnabled(uiSettings: IUiSettingsClient): boolean { + return uiSettings.get(HOMEPAGE_FEATURE_FLAG_ID, false); +} diff --git a/x-pack/plugins/search_homepage/public/hooks/use_kibana.ts b/x-pack/plugins/search_homepage/public/hooks/use_kibana.ts new file mode 100644 index 00000000000000..b22c7b4ed9d7fd --- /dev/null +++ b/x-pack/plugins/search_homepage/public/hooks/use_kibana.ts @@ -0,0 +1,11 @@ +/* + * 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 { useKibana as _useKibana } from '@kbn/kibana-react-plugin/public'; +import { SearchHomepageServicesContext } from '../types'; + +export const useKibana = () => _useKibana(); diff --git a/x-pack/plugins/search_homepage/public/index.ts b/x-pack/plugins/search_homepage/public/index.ts new file mode 100644 index 00000000000000..b5133bb5064066 --- /dev/null +++ b/x-pack/plugins/search_homepage/public/index.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 { PluginInitializerContext } from '@kbn/core/public'; + +import { SearchHomepagePlugin } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new SearchHomepagePlugin(initializerContext); +} + +export type { + SearchHomepagePluginSetup, + SearchHomepagePluginStart, + SearchHomepageAppInfo, +} from './types'; diff --git a/x-pack/plugins/search_homepage/public/plugin.ts b/x-pack/plugins/search_homepage/public/plugin.ts new file mode 100644 index 00000000000000..ebb3ef8ed822c1 --- /dev/null +++ b/x-pack/plugins/search_homepage/public/plugin.ts @@ -0,0 +1,80 @@ +/* + * 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 { + CoreSetup, + Plugin, + CoreStart, + AppMountParameters, + PluginInitializerContext, +} from '@kbn/core/public'; +import { i18n } from '@kbn/i18n'; +import { PLUGIN_ID } from '../common'; + +import { SearchHomepage } from './embeddable'; +import { isHomepageEnabled } from './feature_flags'; +import { + SearchHomepageConfigType, + SearchHomepagePluginSetup, + SearchHomepagePluginStart, + SearchHomepageAppPluginStartDependencies, + SearchHomepageAppInfo, +} from './types'; + +const appInfo: SearchHomepageAppInfo = { + id: PLUGIN_ID, + appRoute: '/app/elasticsearch/home', + title: i18n.translate('xpack.searchHomepage.appTitle', { defaultMessage: 'Home' }), +}; + +export class SearchHomepagePlugin + implements Plugin +{ + private readonly config: SearchHomepageConfigType; + constructor(initializerContext: PluginInitializerContext) { + this.config = initializerContext.config.get(); + } + + public setup( + core: CoreSetup + ) { + const result: SearchHomepagePluginSetup = { + app: appInfo, + isHomepageFeatureEnabled() { + return isHomepageEnabled(core.uiSettings); + }, + }; + if (!this.config.ui?.enabled) return result; + if (!isHomepageEnabled(core.uiSettings)) return result; + + core.application.register({ + ...result.app, + async mount({ element, history }: AppMountParameters) { + const { renderApp } = await import('./application'); + const [coreStart, depsStart] = await core.getStartServices(); + const startDeps: SearchHomepageAppPluginStartDependencies = { + ...depsStart, + history, + }; + + return renderApp(coreStart, startDeps, element); + }, + }); + + return result; + } + + public start(core: CoreStart) { + return { + app: appInfo, + isHomepageFeatureEnabled() { + return isHomepageEnabled(core.uiSettings); + }, + SearchHomepage, + }; + } +} diff --git a/x-pack/plugins/search_homepage/public/router.tsx b/x-pack/plugins/search_homepage/public/router.tsx new file mode 100644 index 00000000000000..e4db94ebde4aee --- /dev/null +++ b/x-pack/plugins/search_homepage/public/router.tsx @@ -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 React from 'react'; +import { Route, Routes } from '@kbn/shared-ux-router'; + +import { SearchHomepagePage } from './components/search_homepage'; + +export const HomepageRouter = () => ( + + + + + +); diff --git a/x-pack/plugins/search_homepage/public/types.ts b/x-pack/plugins/search_homepage/public/types.ts new file mode 100644 index 00000000000000..de5283abfc61d5 --- /dev/null +++ b/x-pack/plugins/search_homepage/public/types.ts @@ -0,0 +1,74 @@ +/* + * 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 { ComponentProps, FC } from 'react'; +import type { CloudSetup } from '@kbn/cloud-plugin/public'; +import type { ConsolePluginStart } from '@kbn/console-plugin/public'; +import type { AppMountParameters, HttpStart } from '@kbn/core/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; +import type { App } from './components/stack_app'; + +export interface SearchHomepageConfigType { + ui: { + enabled: boolean; + }; +} + +export interface SearchHomepageAppInfo { + appRoute: string; + id: string; + title: string; +} + +export interface SearchHomepagePluginSetup { + /** + * Search Homepage shared information for the Kibana application. + * Used to ensure the stack and serverless apps have the same route + * and deep links. + */ + app: SearchHomepageAppInfo; + /** + * Checks if the Search Homepage feature flag is currently enabled. + * @returns true if Search Homepage feature is enabled + */ + isHomepageFeatureEnabled: () => boolean; +} + +export interface SearchHomepagePluginStart { + /** + * Search Homepage shared information for the Kibana application. + * Used to ensure the stack and serverless apps have the same route + * and deep links. + */ + app: SearchHomepageAppInfo; + /** + * Checks if the Search Homepage feature flag is currently enabled. + * @returns true if Search Homepage feature is enabled + */ + isHomepageFeatureEnabled: () => boolean; + /** + * SearchHomepage shared component, used to render the search homepage in + * the Stack search plugin + */ + SearchHomepage: FC>; +} + +export interface SearchHomepageAppPluginStartDependencies { + history: AppMountParameters['history']; + usageCollection?: UsageCollectionStart; + share: SharePluginStart; + console?: ConsolePluginStart; +} + +export interface SearchHomepageServicesContext { + http: HttpStart; + share: SharePluginStart; + cloud?: CloudSetup; + usageCollection?: UsageCollectionStart; + console?: ConsolePluginStart; +} diff --git a/x-pack/plugins/search_homepage/server/config.ts b/x-pack/plugins/search_homepage/server/config.ts new file mode 100644 index 00000000000000..3e068a719f0467 --- /dev/null +++ b/x-pack/plugins/search_homepage/server/config.ts @@ -0,0 +1,27 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import { PluginConfigDescriptor } from '@kbn/core/server'; + +export * from './types'; + +const configSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), + ui: schema.object({ + enabled: schema.boolean({ defaultValue: false }), + }), +}); + +export type SearchHomepageConfig = TypeOf; + +export const config: PluginConfigDescriptor = { + exposeToBrowser: { + ui: true, + }, + schema: configSchema, +}; diff --git a/x-pack/plugins/search_homepage/server/index.ts b/x-pack/plugins/search_homepage/server/index.ts new file mode 100644 index 00000000000000..864af85c0a2fb5 --- /dev/null +++ b/x-pack/plugins/search_homepage/server/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PluginInitializerContext } from '@kbn/core/server'; + +export { config } from './config'; + +export async function plugin(initializerContext: PluginInitializerContext) { + const { SearchHomepagePlugin } = await import('./plugin'); + return new SearchHomepagePlugin(initializerContext); +} + +export type { SearchHomepagePluginSetup, SearchHomepagePluginStart } from './types'; diff --git a/x-pack/plugins/search_homepage/server/plugin.ts b/x-pack/plugins/search_homepage/server/plugin.ts new file mode 100644 index 00000000000000..f446ba4e41fd35 --- /dev/null +++ b/x-pack/plugins/search_homepage/server/plugin.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server'; + +import { SearchHomepagePluginSetup, SearchHomepagePluginStart } from './types'; + +export class SearchHomepagePlugin + implements Plugin +{ + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup<{}, SearchHomepagePluginStart>) { + this.logger.debug('searchHomepage: Setup'); + return {}; + } + + public start(core: CoreStart) { + return {}; + } +} diff --git a/x-pack/plugins/search_homepage/server/types.ts b/x-pack/plugins/search_homepage/server/types.ts new file mode 100644 index 00000000000000..c4e5d469594222 --- /dev/null +++ b/x-pack/plugins/search_homepage/server/types.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SearchHomepagePluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SearchHomepagePluginStart {} diff --git a/x-pack/plugins/search_homepage/tsconfig.json b/x-pack/plugins/search_homepage/tsconfig.json new file mode 100644 index 00000000000000..9f084b32f7d3b3 --- /dev/null +++ b/x-pack/plugins/search_homepage/tsconfig.json @@ -0,0 +1,30 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + }, + "include": [ + "__mocks__/**/*", + "common/**/*", + "public/**/*", + "server/**/*", + ], + "kbn_references": [ + "@kbn/core", + "@kbn/react-kibana-context-render", + "@kbn/kibana-react-plugin", + "@kbn/i18n-react", + "@kbn/shared-ux-router", + "@kbn/shared-ux-page-kibana-template", + "@kbn/shared-ux-utility", + "@kbn/i18n", + "@kbn/cloud-plugin", + "@kbn/console-plugin", + "@kbn/share-plugin", + "@kbn/usage-collection-plugin", + "@kbn/config-schema", + ], + "exclude": [ + "target/**/*", + ] +} diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc index 3a98a87c032a49..04002ee897cf4e 100644 --- a/x-pack/plugins/serverless_search/kibana.jsonc +++ b/x-pack/plugins/serverless_search/kibana.jsonc @@ -29,6 +29,7 @@ "optionalPlugins": [ "indexManagement", "searchConnectors", + "searchHomepage", "searchInferenceEndpoints", "usageCollection" ], diff --git a/x-pack/plugins/serverless_search/public/navigation_tree.ts b/x-pack/plugins/serverless_search/public/navigation_tree.ts index d21eee8de9c194..f5618e8b83e058 100644 --- a/x-pack/plugins/serverless_search/public/navigation_tree.ts +++ b/x-pack/plugins/serverless_search/public/navigation_tree.ts @@ -9,7 +9,7 @@ import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser'; import { i18n } from '@kbn/i18n'; import { CONNECTORS_LABEL } from '../common/i18n_string'; -export const navigationTree: NavigationTreeDefinition = { +export const navigationTree = (useSearchHomepage: boolean = false): NavigationTreeDefinition => ({ body: [ { type: 'navGroup', @@ -25,7 +25,7 @@ export const navigationTree: NavigationTreeDefinition = { title: i18n.translate('xpack.serverlessSearch.nav.home', { defaultMessage: 'Home', }), - link: 'serverlessElasticsearch', + link: useSearchHomepage ? 'searchHomepage' : 'serverlessElasticsearch', spaceBefore: 'm', }, { @@ -149,4 +149,4 @@ export const navigationTree: NavigationTreeDefinition = { ], }, ], -}; +}); diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts index d9019f911444a7..e72e1a4575079a 100644 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -43,6 +43,9 @@ export class ServerlessSearchPlugin core: CoreSetup, setupDeps: ServerlessSearchPluginSetupDependencies ): ServerlessSearchPluginSetup { + const { searchHomepage } = setupDeps; + const useSearchHomepage = searchHomepage && searchHomepage.isHomepageFeatureEnabled(); + const queryClient = new QueryClient({ mutationCache: new MutationCache({ onError: (error) => { @@ -69,6 +72,24 @@ export class ServerlessSearchPlugin }, }), }); + if (useSearchHomepage) { + core.application.register({ + id: 'serverlessHomeRedirect', + title: i18n.translate('xpack.serverlessSearch.app.home.title', { + defaultMessage: 'Home', + }), + appRoute: '/app/elasticsearch', + euiIconType: 'logoElastic', + category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + visibleIn: [], + async mount({}: AppMountParameters) { + const [coreStart] = await core.getStartServices(); + coreStart.application.navigateToApp('searchHomepage'); + return () => {}; + }, + }); + } + core.application.register({ id: 'serverlessElasticsearch', title: i18n.translate('xpack.serverlessSearch.app.elasticsearch.title', { @@ -76,7 +97,7 @@ export class ServerlessSearchPlugin }), euiIconType: 'logoElastic', category: DEFAULT_APP_CATEGORIES.enterpriseSearch, - appRoute: '/app/elasticsearch', + appRoute: useSearchHomepage ? '/app/elasticsearch/getting_started' : '/app/elasticsearch', async mount({ element, history }: AppMountParameters) { const { renderApp } = await import('./application/elasticsearch'); const [coreStart, services] = await core.getStartServices(); @@ -121,10 +142,12 @@ export class ServerlessSearchPlugin core: CoreStart, services: ServerlessSearchPluginStartDependencies ): ServerlessSearchPluginStart { - const { serverless, management, indexManagement, security } = services; - serverless.setProjectHome('/app/elasticsearch'); + const { serverless, management, indexManagement, security, searchHomepage } = services; + const useSearchHomepage = searchHomepage && searchHomepage.isHomepageFeatureEnabled(); + + serverless.setProjectHome(useSearchHomepage ? '/app/elasticsearch/home' : '/app/elasticsearch'); - const navigationTree$ = of(navigationTree); + const navigationTree$ = of(navigationTree(searchHomepage?.isHomepageFeatureEnabled() ?? false)); serverless.initNavigation('search', navigationTree$, { dataTestSubj: 'svlSearchSideNav' }); const extendCardNavDefinitions = serverless.getNavigationCards( diff --git a/x-pack/plugins/serverless_search/public/types.ts b/x-pack/plugins/serverless_search/public/types.ts index e4eab5fbfd61d4..d3011210c524f9 100644 --- a/x-pack/plugins/serverless_search/public/types.ts +++ b/x-pack/plugins/serverless_search/public/types.ts @@ -5,16 +5,20 @@ * 2.0. */ -import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; -import { ConsolePluginStart } from '@kbn/console-plugin/public'; -import { SearchPlaygroundPluginStart } from '@kbn/search-playground/public'; -import { SearchInferenceEndpointsPluginStart } from '@kbn/search-inference-endpoints/public'; -import { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public'; -import { SecurityPluginStart } from '@kbn/security-plugin/public'; -import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; -import { SharePluginStart } from '@kbn/share-plugin/public'; -import { IndexManagementPluginStart } from '@kbn/index-management-plugin/public'; +import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; +import type { ConsolePluginStart } from '@kbn/console-plugin/public'; +import type { SearchInferenceEndpointsPluginStart } from '@kbn/search-inference-endpoints/public'; +import type { SearchPlaygroundPluginStart } from '@kbn/search-playground/public'; +import type { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public'; +import type { SecurityPluginStart } from '@kbn/security-plugin/public'; +import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; +import type { IndexManagementPluginStart } from '@kbn/index-management-plugin/public'; import type { DiscoverSetup } from '@kbn/discover-plugin/public'; +import type { + SearchHomepagePluginSetup, + SearchHomepagePluginStart, +} from '@kbn/search-homepage/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessSearchPluginSetup {} @@ -27,6 +31,7 @@ export interface ServerlessSearchPluginSetupDependencies { management: ManagementSetup; serverless: ServerlessPluginSetup; discover: DiscoverSetup; + searchHomepage?: SearchHomepagePluginSetup; } export interface ServerlessSearchPluginStartDependencies { @@ -39,4 +44,5 @@ export interface ServerlessSearchPluginStartDependencies { serverless: ServerlessPluginStart; share: SharePluginStart; indexManagement?: IndexManagementPluginStart; + searchHomepage?: SearchHomepagePluginStart; } diff --git a/x-pack/plugins/serverless_search/tsconfig.json b/x-pack/plugins/serverless_search/tsconfig.json index 8cf2dec121d46e..418dcb5fc6f5c1 100644 --- a/x-pack/plugins/serverless_search/tsconfig.json +++ b/x-pack/plugins/serverless_search/tsconfig.json @@ -50,5 +50,6 @@ "@kbn/react-kibana-context-render", "@kbn/search-playground", "@kbn/search-inference-endpoints", + "@kbn/search-homepage", ] } diff --git a/x-pack/test_serverless/functional/page_objects/index.ts b/x-pack/test_serverless/functional/page_objects/index.ts index f1604d48508e2f..94e02f9c5e4551 100644 --- a/x-pack/test_serverless/functional/page_objects/index.ts +++ b/x-pack/test_serverless/functional/page_objects/index.ts @@ -21,6 +21,7 @@ import { SvlRuleDetailsPageProvider } from './svl_rule_details_ui_page'; import { SvlSearchConnectorsPageProvider } from './svl_search_connectors_page'; import { SvlManagementPageProvider } from './svl_management_page'; import { SvlIngestPipelines } from './svl_ingest_pipelines'; +import { SvlSearchHomePageProvider } from './svl_search_homepage'; export const pageObjects = { ...xpackFunctionalPageObjects, @@ -38,4 +39,5 @@ export const pageObjects = { svlRuleDetailsUI: SvlRuleDetailsPageProvider, svlManagementPage: SvlManagementPageProvider, svlIngestPipelines: SvlIngestPipelines, + svlSearchHomePage: SvlSearchHomePageProvider, }; diff --git a/x-pack/test_serverless/functional/page_objects/svl_search_homepage.ts b/x-pack/test_serverless/functional/page_objects/svl_search_homepage.ts new file mode 100644 index 00000000000000..eeb1b6de731f9d --- /dev/null +++ b/x-pack/test_serverless/functional/page_objects/svl_search_homepage.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; + +export function SvlSearchHomePageProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + + return { + async expectToBeOnHomepage() { + expect(await browser.getCurrentUrl()).contain('/app/elasticsearch/home'); + }, + async expectToNotBeOnHomepage() { + expect(await browser.getCurrentUrl()).not.contain('/app/elasticsearch/home'); + }, + async expectHomepageHeader() { + await testSubjects.existOrFail('search-homepage-header', { timeout: 2000 }); + }, + }; +} diff --git a/x-pack/test_serverless/functional/services/index.ts b/x-pack/test_serverless/functional/services/index.ts index a1112232377cd0..c63a16b4402f1e 100644 --- a/x-pack/test_serverless/functional/services/index.ts +++ b/x-pack/test_serverless/functional/services/index.ts @@ -16,6 +16,7 @@ import { SvlCommonScreenshotsProvider } from './svl_common_screenshots'; import { SvlCasesServiceProvider } from '../../api_integration/services/svl_cases'; import { MachineLearningProvider } from './ml'; import { LogsSynthtraceProvider } from './log'; +import { UISettingsServiceProvider } from './ui_settings'; export const services = { // deployment agnostic FTR services @@ -30,6 +31,7 @@ export const services = { svlCommonScreenshots: SvlCommonScreenshotsProvider, svlCases: SvlCasesServiceProvider, svlMl: MachineLearningProvider, + uiSettings: UISettingsServiceProvider, // log services svlLogsSynthtraceClient: LogsSynthtraceProvider, }; diff --git a/x-pack/test_serverless/functional/services/ui_settings.ts b/x-pack/test_serverless/functional/services/ui_settings.ts new file mode 100644 index 00000000000000..337930790489db --- /dev/null +++ b/x-pack/test_serverless/functional/services/ui_settings.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; +import { RoleCredentials } from '../../shared/services'; + +export function UISettingsServiceProvider({ getService }: FtrProviderContext) { + const svlCommonApi = getService('svlCommonApi'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + + return { + async setUiSetting(role: RoleCredentials, settingId: string, value: unknown) { + await supertestWithoutAuth + .post(`/internal/kibana/settings/${settingId}`) + .set(svlCommonApi.getInternalRequestHeader()) + .set(role.apiKeyHeader) + .send({ value }) + .expect(200); + }, + async deleteUISetting(role: RoleCredentials, settingId: string) { + await supertestWithoutAuth + .delete(`/internal/kibana/settings/${settingId}`) + .set(svlCommonApi.getInternalRequestHeader()) + .set(role.apiKeyHeader) + .expect(200); + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/search/index.ts b/x-pack/test_serverless/functional/test_suites/search/index.ts index 455acc04044299..8c3cfd83e04e97 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.ts @@ -23,5 +23,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./playground_overview')); loadTestFile(require.resolve('./ml')); + loadTestFile(require.resolve('./search_homepage')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts b/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts new file mode 100644 index 00000000000000..3138e0e7f0242f --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts @@ -0,0 +1,58 @@ +/* + * 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'; +import { RoleCredentials } from '../../../shared/services'; + +import { testHasEmbeddedConsole } from './embedded_console'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'svlSearchHomePage']); + const svlUserManager = getService('svlUserManager'); + const uiSettings = getService('uiSettings'); + let roleAuthc: RoleCredentials; + + const HOMEPAGE_FF_UI_SETTING = 'searchHomepage:homepageEnabled'; + describe('Search Homepage', function () { + this.tags('skipMKI'); + before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + // Enable Homepage Feature Flag + await uiSettings.setUiSetting(roleAuthc, HOMEPAGE_FF_UI_SETTING, true); + + await pageObjects.svlCommonPage.login(); + }); + + after(async () => { + if (!roleAuthc) return; + + // Disable Homepage Feature Flag + await uiSettings.deleteUISetting(roleAuthc, HOMEPAGE_FF_UI_SETTING); + + await pageObjects.svlCommonPage.forceLogout(); + }); + + it('has search homepage with Home sidenav', async () => { + pageObjects.svlSearchHomePage.expectToBeOnHomepage(); + pageObjects.svlSearchHomePage.expectHomepageHeader(); + // Navigate to another page + await pageObjects.svlCommonNavigation.sidenav.clickLink({ + deepLinkId: 'serverlessConnectors', + }); + pageObjects.svlSearchHomePage.expectToNotBeOnHomepage(); + // Click Home in Side nav + await pageObjects.svlCommonNavigation.sidenav.clickLink({ + deepLinkId: 'searchHomepage', + }); + pageObjects.svlSearchHomePage.expectToBeOnHomepage(); + }); + + it('has embedded dev console', async () => { + testHasEmbeddedConsole(pageObjects); + }); + }); +} diff --git a/yarn.lock b/yarn.lock index 64ba753c576951..d1dec3cae024ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6056,6 +6056,10 @@ version "0.0.0" uid "" +"@kbn/search-homepage@link:x-pack/plugins/search_homepage": + version "0.0.0" + uid "" + "@kbn/search-index-documents@link:packages/kbn-search-index-documents": version "0.0.0" uid "" From 45b8c7e1519f83d3b942e37c872a1700ac9f119a Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Wed, 19 Jun 2024 13:04:45 +0200 Subject: [PATCH 087/123] [ML] AIOps: Fix log rate analysis alert details page embedding. (#186371) ## Summary Fixes the log rate analysis embedding in the O11y alert details page, a regression caused by #180969. The refactor in the linked PR moved the data fetching for the histogram chart higher up in the component tree and it was then missing from the embedded variant. ### Checklist - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../log_rate_analysis_content.tsx | 6 +- .../log_rate_analysis_content_wrapper.tsx | 6 +- ...ate_analysis_document_count_chart_data.tsx | 71 +++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_document_count_chart_data.tsx diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx index a62191ed5a02ef..abeb4c603b4e69 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx @@ -8,7 +8,6 @@ import { isEqual } from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, type FC } from 'react'; import { EuiButton, EuiEmptyPrompt, EuiHorizontalRule, EuiPanel } from '@elastic/eui'; -import type { Moment } from 'moment'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { BarStyleAccessor } from '@elastic/charts/dist/chart_types/xy_chart/utils/specs'; @@ -37,7 +36,7 @@ import { type LogRateAnalysisResultsData, } from '../log_rate_analysis_results'; -const DEFAULT_SEARCH_QUERY: estypes.QueryDslQueryContainer = { match_all: {} }; +export const DEFAULT_SEARCH_QUERY: estypes.QueryDslQueryContainer = { match_all: {} }; const DEFAULT_SEARCH_BAR_QUERY: estypes.QueryDslQueryContainer = { bool: { filter: [], @@ -51,8 +50,6 @@ const DEFAULT_SEARCH_BAR_QUERY: estypes.QueryDslQueryContainer = { }; export interface LogRateAnalysisContentProps { - /** Optional time range override */ - timeRange?: { min: Moment; max: Moment }; /** Elasticsearch query to pass to analysis endpoint */ esSearchQuery?: estypes.QueryDslQueryContainer; /** Optional color override for the default bar color for charts */ @@ -68,7 +65,6 @@ export interface LogRateAnalysisContentProps { } export const LogRateAnalysisContent: FC = ({ - timeRange, esSearchQuery = DEFAULT_SEARCH_QUERY, barColorOverride, barHighlightColorOverride, diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx index e9f623ecf0f178..dace975115deb4 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx @@ -27,6 +27,7 @@ import { AIOPS_STORAGE_KEYS } from '../../../types/storage'; import type { LogRateAnalysisResultsData } from '../log_rate_analysis_results'; +import { LogRateAnalysisDocumentCountChartData } from './log_rate_analysis_document_count_chart_data'; import { LogRateAnalysisContent } from './log_rate_analysis_content'; const localStorage = new Storage(window.localStorage); @@ -93,9 +94,12 @@ export const LogRateAnalysisContentWrapper: FC - + = ({ timeRange, esSearchQuery }) => { + const { dataView } = useDataSource(); + + const currentSelectedGroup = useCurrentSelectedGroup(); + const currentSelectedSignificantItem = useCurrentSelectedSignificantItem(); + const dispatch = useAppDispatch(); + + const { documentStats, earliest, latest, intervalMs } = useData( + dataView, + 'log_rate_analysis', + esSearchQuery ?? DEFAULT_SEARCH_QUERY, + undefined, + currentSelectedSignificantItem, + currentSelectedGroup, + undefined, + true, + timeRange + ); + + // TODO Since `useData` isn't just used within Log Rate Analysis, this is a bit of + // a workaround to pass the result on to the redux store. At least this ensures + // we now use `useData` only once across Log Rate Analysis! Originally `useData` + // was quite general, but over time it got quite some specific features used + // across Log Rate Analysis and Pattern Analysis. We discussed that we should + // split this up into more specific hooks. + useEffect(() => { + dispatch( + setDocumentCountChartData({ + earliest, + latest, + intervalMs, + documentStats, + }) + ); + }, [documentStats, dispatch, earliest, intervalMs, latest]); + + return null; +}; From 36c2d128a06077f328a81adb3b7ce12b4af3dc15 Mon Sep 17 00:00:00 2001 From: Bena Kansara <69037875+benakansara@users.noreply.github.com> Date: Wed, 19 Jun 2024 13:49:32 +0200 Subject: [PATCH 088/123] [Custom threshold/Metric threshold] Use emotion instead of styled component for auto suggestion (#186422) Fixes https://github.com/elastic/kibana/issues/186248 for Custom threshold and Metric threshold (custom equation use case) rules ### Custom threshold rule https://github.com/elastic/kibana/assets/69037875/dd25a874-4c7b-4cb2-9319-82ac5977e5d9 ### Metric threshold rule (Custom equation) https://github.com/elastic/kibana/assets/69037875/14cb0394-632c-418c-813e-6c4eef6e44fb --------- Co-authored-by: jennypavlova --- .../metrics_explorer/components/kuery_bar.tsx | 6 +- .../autocomplete_field/autocomplete_field.tsx | 53 +++--- .../autocomplete_field/suggestion_item.tsx | 151 ++++++++++-------- .../components/rule_kql_filter/kuery_bar.tsx | 4 + 4 files changed, 124 insertions(+), 90 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx index b6918ab140df13..a75940714dec64 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx @@ -9,9 +9,10 @@ import { i18n } from '@kbn/i18n'; import { fromKueryExpression } from '@kbn/es-query'; import React, { useEffect, useState } from 'react'; import { QuerySuggestion } from '@kbn/unified-search-plugin/public'; +import { AutocompleteField } from '@kbn/observability-plugin/public'; +import { useEuiTheme } from '@elastic/eui'; import { useMetricsDataViewContext } from '../../../../containers/metrics_source'; import { WithKueryAutocompletion } from '../../../../containers/with_kuery_autocompletion'; -import { AutocompleteField } from '../../../../components/autocomplete_field'; type LoadSuggestionsFn = ( e: string, @@ -58,6 +59,8 @@ export const MetricsExplorerKueryBar = ({ } }, [value]); + const { euiTheme } = useEuiTheme(); + const handleChange = (query: string) => { setValidation(validateQuery(query)); setDraftQuery(query); @@ -87,6 +90,7 @@ export const MetricsExplorerKueryBar = ({ placeholder={placeholder || defaultPlaceholder} suggestions={suggestions} value={draftQuery} + theme={euiTheme} /> )} diff --git a/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/autocomplete_field/autocomplete_field.tsx b/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/autocomplete_field/autocomplete_field.tsx index 4aaa44e7421087..e8545276c572a3 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/autocomplete_field/autocomplete_field.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/autocomplete_field/autocomplete_field.tsx @@ -5,12 +5,12 @@ * 2.0. */ -import { EuiFieldSearch, EuiOutsideClickDetector, EuiPanel } from '@elastic/eui'; +import { EuiFieldSearch, EuiOutsideClickDetector, EuiPanel, EuiThemeComputed } from '@elastic/eui'; import React from 'react'; import { QuerySuggestion } from '@kbn/unified-search-plugin/public'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; - +import { css } from '@emotion/react'; import { SuggestionItem } from './suggestion_item'; + export type StateUpdater = ( prevState: Readonly, prevProps: Readonly @@ -34,6 +34,7 @@ interface AutocompleteFieldProps { autoFocus?: boolean; 'aria-label'?: string; compressed?: boolean; + theme?: EuiThemeComputed; } interface AutocompleteFieldState { @@ -64,12 +65,17 @@ export class AutocompleteField extends React.Component< disabled, 'aria-label': ariaLabel, compressed, + theme, } = this.props; const { areSuggestionsVisible, selectedIndex } = this.state; return ( - +
{areSuggestionsVisible && !isLoadingSuggestions && suggestions.length > 0 ? ( - + {suggestions.map((suggestion, suggestionIndex) => ( ))} - + ) : null} - +
); } @@ -310,20 +330,3 @@ const withUnfocused = (state: AutocompleteFieldState) => ({ ...state, isFocused: false, }); - -const AutocompleteContainer = euiStyled.div` - position: relative; -`; - -const SuggestionsPanel = euiStyled(EuiPanel).attrs(() => ({ - paddingSize: 'none', - hasShadow: true, -}))` - position: absolute; - width: 100%; - margin-top: 2px; - overflow-x: hidden; - overflow-y: scroll; - z-index: ${(props) => props.theme.eui.euiZLevel1}; - max-height: 322px; -`; diff --git a/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/autocomplete_field/suggestion_item.tsx b/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/autocomplete_field/suggestion_item.tsx index 67e4c879c72433..2eb5165b20e891 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/autocomplete_field/suggestion_item.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/autocomplete_field/suggestion_item.tsx @@ -6,29 +6,96 @@ */ import React from 'react'; -import { EuiIcon } from '@elastic/eui'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { EuiIcon, euiPaletteColorBlind, EuiThemeComputed, useEuiTheme } from '@elastic/eui'; import { QuerySuggestion, QuerySuggestionTypes } from '@kbn/unified-search-plugin/public'; import { transparentize } from 'polished'; +import { css } from '@emotion/react'; interface Props { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; + onKeyDown?: React.KeyboardEventHandler; suggestion: QuerySuggestion; } export function SuggestionItem(props: Props) { - const { isSelected, onClick, onMouseEnter, suggestion } = props; + const { isSelected, onClick, onMouseEnter, onKeyDown, suggestion } = props; + const { euiTheme } = useEuiTheme(); + + const suggestionItemContainerCss = ` + display: flex; + flex-direction: row; + font-size: ${euiTheme.font.scale.s}; + height: ${euiTheme.size.xl}; + white-space: nowrap; + background-color: ${isSelected ? euiTheme.colors.lightestShade : 'transparent'}; + `; + + const suggestionItemFieldCss = ` + align-items: center; + cursor: pointer; + display: flex; + flex-direction: row; + height: ${euiTheme.size.xl}; + padding: ${euiTheme.size.xs}; + `; + + const suggestionItemIconFieldCss = ` + background-color: ${transparentize(0.9, getEuiIconColor(euiTheme, suggestion.type))}; + color: ${getEuiIconColor(euiTheme, suggestion.type)}; + flex: 0 0 auto; + justify-content: center; + width: ${euiTheme.size.xl}; + `; + + const suggestionItemTextFieldCss = ` + flex: 2 0 0; + font-family: ${euiTheme.font.familyCode}; + `; + + const suggestionItemDescriptionFieldCss = ` + flex: 3 0 0; + p { + display: inline; + span { + font-family: ${euiTheme.font.familyCode}; + } + } + `; return ( - - +
+
- - {suggestion.text} - {suggestion.description} - +
+
+ {suggestion.text} +
+
+ {suggestion.description} +
+
); } @@ -36,55 +103,6 @@ SuggestionItem.defaultProps = { isSelected: false, }; -const SuggestionItemContainer = euiStyled.div<{ - isSelected?: boolean; -}>` - display: flex; - flex-direction: row; - font-size: ${(props) => props.theme.eui.euiFontSizeS}; - height: ${(props) => props.theme.eui.euiSizeXL}; - white-space: nowrap; - background-color: ${(props) => - props.isSelected ? props.theme.eui.euiColorLightestShade : 'transparent'}; -`; - -const SuggestionItemField = euiStyled.div` - align-items: center; - cursor: pointer; - display: flex; - flex-direction: row; - height: ${(props) => props.theme.eui.euiSizeXL}; - padding: ${(props) => props.theme.eui.euiSizeXS}; -`; - -const SuggestionItemIconField = euiStyled(SuggestionItemField)<{ - suggestionType: QuerySuggestionTypes; -}>` - background-color: ${(props) => - transparentize(0.9, getEuiIconColor(props.theme, props.suggestionType))}; - color: ${(props) => getEuiIconColor(props.theme, props.suggestionType)}; - flex: 0 0 auto; - justify-content: center; - width: ${(props) => props.theme.eui.euiSizeXL}; -`; - -const SuggestionItemTextField = euiStyled(SuggestionItemField)` - flex: 2 0 0; - font-family: ${(props) => props.theme.eui.euiCodeFontFamily}; -`; - -const SuggestionItemDescriptionField = euiStyled(SuggestionItemField)` - flex: 3 0 0; - - p { - display: inline; - - span { - font-family: ${(props) => props.theme.eui.euiCodeFontFamily}; - } - } -`; - const getEuiIconType = (suggestionType: QuerySuggestionTypes) => { switch (suggestionType) { case QuerySuggestionTypes.Field: @@ -102,18 +120,23 @@ const getEuiIconType = (suggestionType: QuerySuggestionTypes) => { } }; -const getEuiIconColor = (theme: any, suggestionType: QuerySuggestionTypes): string => { +const getEuiIconColor = ( + euiTheme: EuiThemeComputed, + suggestionType: QuerySuggestionTypes +): string => { + const palette = euiPaletteColorBlind(); + switch (suggestionType) { case QuerySuggestionTypes.Field: - return theme?.eui.euiColorVis7; + return palette[7]; case QuerySuggestionTypes.Value: - return theme?.eui.euiColorVis0; + return palette[0]; case QuerySuggestionTypes.Operator: - return theme?.eui.euiColorVis1; + return palette[1]; case QuerySuggestionTypes.Conjunction: - return theme?.eui.euiColorVis2; + return palette[2]; case QuerySuggestionTypes.RecentSearch: default: - return theme?.eui.euiColorMediumShade; + return euiTheme.colors.mediumShade; } }; diff --git a/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/kuery_bar.tsx b/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/kuery_bar.tsx index 9c16d4d7b69af9..26115ec331021e 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/kuery_bar.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_kql_filter/kuery_bar.tsx @@ -10,6 +10,7 @@ import React, { useEffect, useState } from 'react'; import { DataViewBase } from '@kbn/es-query'; import { QuerySuggestion } from '@kbn/unified-search-plugin/public'; +import { useEuiTheme } from '@elastic/eui'; import { WithKueryAutocompletion } from './with_kuery_autocompletion'; import { AutocompleteField } from './autocomplete_field'; @@ -59,6 +60,8 @@ export function RuleFlyoutKueryBar({ } }, [value]); + const { euiTheme } = useEuiTheme(); + const handleChange = (query: string) => { setValidation(validateQuery(query)); setDraftQuery(query); @@ -86,6 +89,7 @@ export function RuleFlyoutKueryBar({ placeholder={placeholder} suggestions={suggestions} value={draftQuery} + theme={euiTheme} /> )} From 16a3749837127036179b4df551b324692ec55c33 Mon Sep 17 00:00:00 2001 From: Tiago Vila Verde Date: Wed, 19 Jun 2024 14:04:50 +0200 Subject: [PATCH 089/123] [Security Solution][Entity Analytics] Adding Asset Criticality column to All Hosts tab in Explore pages (#186375) This PR adds a new column for Asset Criticality to the "All hosts" tab in the Explore/Hosts page. If any of the hosts has criticality data assigned, it will be displayed in the new column. If no criticality has been assigned, the field is left blank. ![Screenshot 2024-06-18 at 15 00 46](https://github.com/elastic/kibana/assets/2423976/dc6e76c9-ceed-4da6-905c-b374181fe0f3) ### How to test 1. Make sure you have test data with Asset Criticality. - Either use the [datagen tool](https://github.com/elastic/security-documents-generator) or just make sure to assign criticality to already existing hosts 2. Enable Asset Criticality settings in `Stack Management > Kibana > Advanced Settings` 3. Navigate to `Explore > Hosts > All Hosts` --- .../search_strategy/asset_criticality/all.ts | 20 +++++ .../hosts/components/hosts_table/columns.tsx | 24 +++++- .../components/hosts_table/index.test.tsx | 60 +++++++++++++++ .../hosts/components/hosts_table/index.tsx | 23 ++++-- .../components/hosts_table/translations.ts | 7 ++ .../query.asset_criticality.dsl.ts | 49 +++++++++++++ .../factory/hosts/all/index.ts | 73 +++++++++++++------ 7 files changed, 228 insertions(+), 28 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/api/search_strategy/asset_criticality/all.ts create mode 100644 x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/asset_criticality/query.asset_criticality.dsl.ts diff --git a/x-pack/plugins/security_solution/common/api/search_strategy/asset_criticality/all.ts b/x-pack/plugins/security_solution/common/api/search_strategy/asset_criticality/all.ts new file mode 100644 index 00000000000000..cbbc885cc60911 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/search_strategy/asset_criticality/all.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 { z } from 'zod'; +import { requestBasicOptionsSchema } from '../model/request_basic_options'; + +export const assetCriticalityRequestOptionsSchema = requestBasicOptionsSchema.extend({ + pagination: z + .object({ + cursorStart: z.number(), + querySize: z.number(), + }) + .optional(), +}); + +export type AssetCriticalityRequestOptions = z.infer; diff --git a/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/columns.tsx b/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/columns.tsx index 270a10b52155a7..6f8e3ad587a0d0 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/columns.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/columns.tsx @@ -7,6 +7,8 @@ import { EuiIcon, EuiLink, EuiText, EuiToolTip } from '@elastic/eui'; import React from 'react'; +import type { CriticalityLevelWithUnassigned } from '../../../../../common/entity_analytics/asset_criticality/types'; +import { AssetCriticalityBadge } from '../../../../entity_analytics/components/asset_criticality'; import { SecurityCellActions, CellActionsMode, @@ -25,7 +27,8 @@ import { ENTITY_RISK_LEVEL } from '../../../../entity_analytics/components/risk_ export const getHostsColumns = ( showRiskColumn: boolean, - dispatchSeverityUpdate: (s: RiskSeverity) => void + dispatchSeverityUpdate: (s: RiskSeverity) => void, + isAssetCriticalityEnabled: boolean ): HostsTableColumns => { const columns: HostsTableColumns = [ { @@ -163,5 +166,24 @@ export const getHostsColumns = ( }); } + if (isAssetCriticalityEnabled) { + columns.push({ + field: 'node.criticality', + name: i18n.ASSET_CRITICALITY, + truncateText: false, + mobileOptions: { show: true }, + sortable: false, + render: (assetCriticality: CriticalityLevelWithUnassigned) => { + if (!assetCriticality) return getEmptyTagValue(); + return ( + + ); + }, + }); + } + return columns; }; diff --git a/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/index.test.tsx b/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/index.test.tsx index d46182ca7f4d91..8d20fed91a66a2 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/index.test.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/index.test.tsx @@ -46,6 +46,16 @@ jest.mock('../../../../helper_hooks', () => ({ useHasSecurityCapability: () => mockUseHasSecurityCapability(), })); +const mockUseUiSetting = jest.fn().mockReturnValue([false]); + +jest.mock('@kbn/kibana-react-plugin/public', () => { + const original = jest.requireActual('@kbn/kibana-react-plugin/public'); + return { + ...original, + useUiSetting$: () => mockUseUiSetting(), + }; +}); + describe('Hosts Table', () => { const loadPage = jest.fn(); const store = createMockStore(); @@ -145,6 +155,56 @@ describe('Hosts Table', () => { expect(queryByTestId('tableHeaderCell_node.riskScore_4')).not.toBeInTheDocument(); }); + test('it renders "Asset Criticality" column when "isPlatinumOrTrialLicense" is truthy, user has risk-entity capability and Asset Criticality is enabled in Kibana settings', () => { + mockUseMlCapabilities.mockReturnValue({ isPlatinumOrTrialLicense: true }); + mockUseHasSecurityCapability.mockReturnValue(true); + mockUseUiSetting.mockReturnValue([true]); + + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('tableHeaderCell_node.criticality_5')).toBeInTheDocument(); + }); + + test('it does not render "Asset Criticality" column when Asset Criticality is not enabled in Kibana settings', () => { + mockUseMlCapabilities.mockReturnValue({ isPlatinumOrTrialLicense: true }); + mockUseHasSecurityCapability.mockReturnValue(true); + mockUseUiSetting.mockReturnValue([false]); + + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('tableHeaderCell_node.criticality_5')).not.toBeInTheDocument(); + }); + describe('Sorting on Table', () => { let wrapper: ReturnType; diff --git a/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/index.tsx b/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/index.tsx index 3c76bc5dcbf9c1..ef9a368dac3700 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/index.tsx @@ -9,6 +9,8 @@ import React, { useMemo, useCallback } from 'react'; import { useDispatch } from 'react-redux'; import type { HostEcs, OsEcs } from '@kbn/securitysolution-ecs'; +import { useUiSetting$ } from '@kbn/kibana-react-plugin/public'; +import type { CriticalityLevelWithUnassigned } from '../../../../../common/entity_analytics/asset_criticality/types'; import { HostsFields } from '../../../../../common/api/search_strategy/hosts/model/sort'; import type { Columns, @@ -27,7 +29,10 @@ import type { HostsSortField, } from '../../../../../common/search_strategy/security_solution/hosts'; import type { Direction, RiskSeverity } from '../../../../../common/search_strategy'; -import { SecurityPageName } from '../../../../../common/constants'; +import { + ENABLE_ASSET_CRITICALITY_SETTING, + SecurityPageName, +} from '../../../../../common/constants'; import { HostsTableType } from '../../store/model'; import { useNavigateTo } from '../../../../common/lib/kibana/hooks'; import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml_capabilities'; @@ -53,7 +58,8 @@ export type HostsTableColumns = [ Columns, Columns, Columns, - Columns? + Columns?, + Columns? ]; const rowItems: ItemsPerRow[] = [ @@ -153,15 +159,22 @@ const HostsTableComponent: React.FC = ({ [dispatch, navigateTo, type] ); + const [isAssetCriticalityEnabled] = useUiSetting$(ENABLE_ASSET_CRITICALITY_SETTING); + const hostsColumns = useMemo( () => getHostsColumns( isPlatinumOrTrialLicense && hasEntityAnalyticsCapability, - dispatchSeverityUpdate + dispatchSeverityUpdate, + isAssetCriticalityEnabled ), - [dispatchSeverityUpdate, isPlatinumOrTrialLicense, hasEntityAnalyticsCapability] + [ + dispatchSeverityUpdate, + isPlatinumOrTrialLicense, + hasEntityAnalyticsCapability, + isAssetCriticalityEnabled, + ] ); - const sorting = useMemo(() => getSorting(sortField, direction), [sortField, direction]); return ( diff --git a/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/translations.ts b/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/translations.ts index 1f81968213b458..c6cc085a61b0b4 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/translations.ts +++ b/x-pack/plugins/security_solution/public/explore/hosts/components/hosts_table/translations.ts @@ -60,3 +60,10 @@ export const ROWS_10 = i18n.translate('xpack.securitySolution.hostsTable.rows', values: { numRows: 10 }, defaultMessage: '{numRows} {numRows, plural, =0 {rows} =1 {row} other {rows}}', }); + +export const ASSET_CRITICALITY = i18n.translate( + 'xpack.securitySolution.hostsTable.assetCriticality', + { + defaultMessage: 'Asset criticality', + } +); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/asset_criticality/query.asset_criticality.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/asset_criticality/query.asset_criticality.dsl.ts new file mode 100644 index 00000000000000..8b081ecd951d74 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/asset_criticality/query.asset_criticality.dsl.ts @@ -0,0 +1,49 @@ +/* + * 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 { AssetCriticalityRequestOptions } from '../../../../../common/api/search_strategy/asset_criticality/all'; +import { createQueryFilterClauses } from '../../../../utils/build_query'; + +export const buildAssetCriticalityQuery = ({ + timerange, + filterQuery, + defaultIndex, + pagination: { querySize, cursorStart } = { + querySize: QUERY_SIZE, + cursorStart: 0, + }, +}: AssetCriticalityRequestOptions) => { + const filter = createQueryFilterClauses(filterQuery); + + if (timerange) { + filter.push({ + range: { + '@timestamp': { + gte: timerange.from, + lte: timerange.to, + format: 'strict_date_optional_time', + }, + }, + }); + } + + const dslQuery = { + index: defaultIndex, + allow_no_indices: false, + ignore_unavailable: true, + track_total_hits: true, + size: querySize, + from: cursorStart, + body: { + query: { bool: { filter } }, + }, + }; + + return dslQuery; +}; + +export const QUERY_SIZE = 10; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts index 1e04b6910601ce..ad60ec516cb53c 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/index.ts @@ -9,6 +9,9 @@ import { getOr } from 'lodash/fp'; import type { IEsSearchResponse } from '@kbn/search-types'; import type { IScopedClusterClient } from '@kbn/core/server'; +import type { AggregationsAggregate, SearchResponse } from '@elastic/elasticsearch/lib/api/types'; +import _ from 'lodash'; +import type { AssetCriticalityRecord } from '../../../../../../common/api/entity_analytics'; import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants'; import type { HostAggEsItem, @@ -32,6 +35,8 @@ import { formatHostEdgesData, HOSTS_FIELDS } from './helpers'; import type { EndpointAppContext } from '../../../../../endpoint/types'; import { buildRiskScoreQuery } from '../../risk_score/all/query.risk_score.dsl'; +import { buildAssetCriticalityQuery } from '../../asset_criticality/query.asset_criticality.dsl'; +import { getAssetCriticalityIndex } from '../../../../../../common/entity_analytics/asset_criticality'; export const allHosts: SecuritySolutionFactory = { buildDsl: (options) => { @@ -97,29 +102,23 @@ async function enhanceEdges( esClient: IScopedClusterClient, isNewRiskScoreModuleInstalled: boolean ): Promise { - const hostRiskData = await getHostRiskData( - esClient, - spaceId, - hostNames, - isNewRiskScoreModuleInstalled - ); - const hostsRiskByHostName: Record | undefined = hostRiskData?.hits.hits.reduce( - (acc, hit) => ({ - ...acc, - [hit._source?.host.name ?? '']: hit._source?.host?.risk?.calculated_level, - }), - {} - ); + const [riskByHostName, criticalityByHostName] = await Promise.all([ + getHostRiskData(esClient, spaceId, hostNames, isNewRiskScoreModuleInstalled).then( + buildRecordFromAggs('host.name', 'host.risk.calculated_level') + ), + getHostCriticalityData(esClient, hostNames).then( + buildRecordFromAggs('id_value', 'criticality_level') + ), + ]); - return hostsRiskByHostName - ? edges.map(({ node, cursor }) => ({ - node: { - ...node, - risk: hostsRiskByHostName[node._id ?? ''], - }, - cursor, - })) - : edges; + return edges.map(({ node, cursor }) => ({ + node: { + ...node, + risk: riskByHostName?.[node._id ?? ''], + criticality: criticalityByHostName?.[node._id ?? ''], + }, + cursor, + })); } export async function getHostRiskData( @@ -145,3 +144,33 @@ export async function getHostRiskData( return undefined; } } + +export async function getHostCriticalityData(esClient: IScopedClusterClient, hostNames: string[]) { + try { + const criticalityResponse = await esClient.asCurrentUser.search( + buildAssetCriticalityQuery({ + defaultIndex: [getAssetCriticalityIndex('default')], // TODO:(@tiansivive) move to constant or import from somewhere else + filterQuery: { terms: { id_value: hostNames } }, + }) + ); + return criticalityResponse; + } catch (error) { + if (error?.meta?.body?.error?.type !== 'index_not_found_exception') { + throw error; + } + return undefined; + } +} + +const buildRecordFromAggs = + (key: string, path: string) => + ( + data: SearchResponse> | undefined + ): Record | undefined => + data?.hits.hits.reduce( + (acc, hit) => ({ + ...acc, + [_.get(hit._source, key) || '']: _.get(hit._source, path), + }), + {} + ); From cc72854dcda09cbafc13ef0d0b51fcbe4d7f93f9 Mon Sep 17 00:00:00 2001 From: Abdul Wahab Zahid Date: Wed, 19 Jun 2024 14:14:38 +0200 Subject: [PATCH 090/123] [Dataset quality] Synthtrace script for load testing Dataset Quality (#184804) This commit adds the synthtrace scenario `logs_traces_hosts` script . It's designed to generate synthetic log, trace, and host data (interlinked via `service.name`, `host.name` and other fields) for testing and development purposes. The script generates data based on a set of predefined scenarios and parameters and prefers to use atomic names over sequentially generated names. For more details, see https://github.com/elastic/kibana/pull/184804. --- .../src/lib/infra/host.ts | 1 + .../src/lib/logs/index.ts | 4 + .../src/scenarios/logs_traces_hosts.ts | 467 ++++++++++++++++++ 3 files changed, 472 insertions(+) create mode 100644 packages/kbn-apm-synthtrace/src/scenarios/logs_traces_hosts.ts diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts index 136b3cf227a9d6..b4425156e67804 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts @@ -16,6 +16,7 @@ interface HostDocument extends Fields { 'host.name': string; 'metricset.name'?: string; 'event.module'?: string; + 'service.name'?: string; } class Host extends Entity { diff --git a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts index a649d60df57a21..489221eea3d7a7 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts @@ -25,11 +25,14 @@ export type LogDocument = Fields & 'host.name'?: string; 'container.id'?: string; 'trace.id'?: string; + 'transaction.id'?: string; 'agent.id'?: string; 'agent.name'?: string; 'orchestrator.cluster.name'?: string; 'orchestrator.cluster.id'?: string; 'orchestrator.resource.id'?: string; + 'kubernetes.pod.uid'?: string; + 'aws.s3.bucket.name'?: string; 'orchestrator.namespace'?: string; 'container.name'?: string; 'cloud.provider'?: string; @@ -40,6 +43,7 @@ export type LogDocument = Fields & 'error.stack_trace'?: string; 'error.exception.stacktrace'?: string; 'error.log.stacktrace'?: string; + 'log.custom': Record; }>; class Log extends Serializable { diff --git a/packages/kbn-apm-synthtrace/src/scenarios/logs_traces_hosts.ts b/packages/kbn-apm-synthtrace/src/scenarios/logs_traces_hosts.ts new file mode 100644 index 00000000000000..a745ef6d2bca2b --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/logs_traces_hosts.ts @@ -0,0 +1,467 @@ +/* + * 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 { + log, + LogDocument, + InfraDocument, + apm, + Instance, + infra, + ApmFields, + generateShortId, +} from '@kbn/apm-synthtrace-client'; +import { Scenario } from '../cli/scenario'; +import { Logger } from '../lib/utils/create_logger'; +import { withClient } from '../lib/utils/with_client'; +import { getSynthtraceEnvironment } from '../lib/utils/get_synthtrace_environment'; + +const ENVIRONMENT = getSynthtraceEnvironment(__filename); + +// Use e.g. # ... --scenarioOpts.numServices=5 --scenarioOpts.customFieldPrefix="metric". See https://github.com/elastic/kibana/pull/184804 for more details. +const DEFAULT_SCENARIO_OPTS = { + numSpaces: 1, + numServices: 10, + numHosts: 10, + numAgents: 5, + numDatasets: 6, // Won't be used if `datasets` option is provided + datasets: undefined, // Provide a list of datasets --scenarioOpts.datasets="apache.access" --scenarioOpts.datasets="nginx.error" to override the default list + degradedRatio: 0.25, // Percentage of logs that are malformed (over limit or mapping conflict) + numCustomFields: 50, // Number of custom field (e.g. `log.custom.field-1: "abc"`) per document + customFieldPrefix: 'field', // Prefix for custom fields (e.g. `log.custom.field-1: "abc"`) + logsInterval: '1m', + logsRate: 1, + ingestHosts: true, + ingestTraces: true, +}; + +const scenario: Scenario = async (runOptions) => { + return { + generate: ({ range, clients: { logsEsClient, infraEsClient, apmEsClient } }) => { + const { + numSpaces, + numServices, + numHosts, + numAgents, + numDatasets, + datasets, + degradedRatio, + numCustomFields, + customFieldPrefix, + logsInterval, + logsRate, + ingestHosts, + ingestTraces, + } = { ...DEFAULT_SCENARIO_OPTS, ...(runOptions.scenarioOpts || {}) }; + const { logger } = runOptions; + + killIfUnknownScenarioOptions(logger, runOptions.scenarioOpts || {}); + + // Infra Hosts + const infraHosts = Array(numHosts) + .fill(0) + .map((_, idx) => infra.host(getRotatedItem(idx, HOSTS, numHosts))); + + const hosts = range + .interval('1m') + .rate(1) + .generator((timestamp) => { + const agent = getRotatedItem(timestamp, AGENTS, numAgents); + const service = getRotatedItem(timestamp, SERVICE_NAMES, numServices); + + return infraHosts.flatMap((host) => + [ + host.cpu().timestamp(timestamp), + host.memory().timestamp(timestamp), + host.network().timestamp(timestamp), + host.load().timestamp(timestamp), + host.filesystem().timestamp(timestamp), + host.diskio().timestamp(timestamp), + ].map((metric) => + metric.defaults({ + 'host.name': host.fields['host.name'], + 'host.hostname': host.fields['host.name'], + 'agent.id': agent.id, + 'service.name': service, + 'system.memory.actual.free': 500 + Math.floor(Math.random() * 500), + 'system.memory.total': 1000, + 'system.cpu.total.norm.pct': 0.5 + Math.random() * 0.25, + }) + ) + ); + }); + + // APM Traces + const instances = [...Array(numServices).keys()].map((index) => { + const agent = getRotatedItem(index, AGENTS, numAgents); + + return apm + .service({ + name: getRotatedItem(index, SERVICE_NAMES, numServices), + environment: ENVIRONMENT, + agentName: agent.name, + }) + .instance(getRotatedItem(index, HOSTS, numHosts)); + }); + const instanceSpans = (instance: Instance) => { + const successfulTraceEvents = range + .interval('1m') + .rate(1) + .generator((timestamp) => { + const isError = Math.random() < 0.5; + const cloudRegion = getRotatedItem(timestamp, CLOUD_REGION, 3); + const agent = getRotatedItem(timestamp, AGENTS, numAgents); + + const transaction = instance + .transaction({ transactionName: getRotatedItem(timestamp, TRANSACTION_NAMES, 3) }) + .timestamp(timestamp) + .duration(1000) + .defaults({ + 'trace.id': `trace-id-${getTimestampBlock(timestamp, 3 * 60 * 1000)}`, + 'transaction.id': `transaction-id-${getTimestampBlock(timestamp, 2 * 60 * 1000)}`, + 'span.id': `span-id-${getTimestampBlock(timestamp, 60 * 1000)}`, + 'agent.name': agent.name, + 'cloud.region': cloudRegion, + 'cloud.provider': getRotatedItem(timestamp, CLOUD_PROVIDERS, 3), + 'cloud.project.id': generateShortId(), + 'cloud.availability_zone': `${cloudRegion}a`, + 'service.name': getRotatedItem(timestamp, SERVICE_NAMES, numServices), + 'service.environment': ENVIRONMENT, + }); + + if (isError) { + transaction.failure().errors( + instance + .error({ + message: '[ResponseError] index_not_found_exception', + type: 'ResponseError', + }) + .timestamp(timestamp) + ); + } else { + transaction.success().children( + instance + .span({ + spanName: 'GET apm-*/_search', + spanType: 'db', + spanSubtype: 'elasticsearch', + }) + .duration(1000) + .success() + .destination('elasticsearch') + .timestamp(timestamp), + instance + .span({ spanName: 'custom_operation', spanType: 'custom' }) + .duration(100) + .success() + .timestamp(timestamp) + ); + } + + return transaction; + }); + + return [successfulTraceEvents]; + }; + + // Logs + const logDatasets = datasets ? (Array.isArray(datasets) ? datasets : [datasets]) : DATASETS; + const numLogDatasets = datasets ? logDatasets.length : numDatasets; + const cloudProjectId = `cloud-project-${generateShortId()}`; + const logs = range + .interval(logsInterval) + .rate(logsRate) + .generator((timestamp, index) => { + const isMalformed = index > 0 && Math.random() < degradedRatio; // `index > 0` to wait for dynamic templates + const cloudRegion = getRotatedItem(timestamp, CLOUD_REGION, 3); + const dataset = getRotatedItem(timestamp, logDatasets, numLogDatasets); + const space = getRotatedItem(timestamp, NAMESPACES, numSpaces); + const hostName = getRotatedItem(timestamp, HOSTS, numHosts); + const agent = getRotatedItem(timestamp, AGENTS, numAgents); + const service = getRotatedItem(timestamp, SERVICE_NAMES, numServices); + const logLevel = getRotatedItem(timestamp, LOG_LEVELS, LOG_LEVELS.length); + const message = `Log message for logs-${dataset}-${space}. logLevel: ${logLevel}. isMalformed: ${isMalformed}. dataset: ${dataset}. space: ${space}. cloudRegion: ${cloudRegion}.`; + const customFields = getExtraFields(numCustomFields, isMalformed, customFieldPrefix); + + return log + .create() + .dataset(dataset) + .message(message) + .logLevel(logLevel) + .namespace(space) + .hostName(hostName) + .service(service) + .containerId(`container.${Math.random() > 0.5 ? 1 : 2}.${hostName}`) + .defaults({ + 'trace.id': `trace-id-${getTimestampBlock(timestamp, 3 * 60 * 1000)}`, + 'transaction.id': `transaction-id-${getTimestampBlock(timestamp, 2 * 60 * 1000)}`, + 'agent.id': agent.id, + 'agent.name': agent.name, + 'container.id': generateShortId(), + 'orchestrator.cluster.name': getRotatedItem(timestamp, CLUSTERS, 3).clusterName, + 'orchestrator.cluster.id': getRotatedItem(timestamp, CLUSTERS, 3).clusterId, + 'orchestrator.resource.id': generateShortId(), + 'kubernetes.pod.uid': `kb.${Math.random() > 0.5 ? 1 : 2}.${hostName}`, + 'aws.s3.bucket.name': `aws.bk.${Math.random() > 0.5 ? 1 : 2}.${hostName}`, + 'cloud.provider': getRotatedItem(timestamp, CLOUD_PROVIDERS, 3), + 'cloud.region': cloudRegion, + 'cloud.availability_zone': `${cloudRegion}a`, + 'cloud.project.id': cloudProjectId, + 'cloud.instance.id': getRotatedItem(timestamp, CLUSTERS, 3).clusterId, + 'log.file.path': `/logs/${generateShortId()}/${logLevel}.txt`, + 'log.custom': customFields, + }) + .timestamp(timestamp); + }); + + return [ + ...(ingestHosts + ? [ + withClient( + infraEsClient, + logger.perf('generating_infra_hosts', () => hosts) + ), + ] + : []), + ...(ingestTraces + ? [ + withClient( + apmEsClient, + logger.perf('generating_apm_events', () => + instances.flatMap((instance) => instanceSpans(instance)) + ) + ), + ] + : []), + withClient( + logsEsClient, + logger.perf('generating_logs', () => logs) + ), + ]; + }, + }; +}; + +export default scenario; + +/** + * The function will pick an item from the list of items and rotate the item based on the index and maxPickCount. + * + * @param index Current running index of the item. Can be any sequential number. + * @param items List of items to pick from. + * @param maxPickCount How many items to pick from the list. If maxPickCount > items.length, then it will pick all items. + */ +function getRotatedItem(index: number, items: T[], maxPickCount: number) { + const normalizedIndex = Math.floor(index > 1000000 ? index / 1000 : index); // To randomize timestamps + const maxLength = Math.min(maxPickCount, items.length); + return items[normalizedIndex % maxLength]; +} + +/** + * The function will return the (passed) timestamp block based on the milliInterval. + * + * @param timestamp The timestamp to get the block for. + * @param milliInterval The interval in milliseconds. E.g. 30000 for 30 second block. + */ +function getTimestampBlock(timestamp: number, milliInterval: number) { + const remainder = timestamp % milliInterval; + return timestamp - remainder; +} + +/** + * Generate extra fields with sequential keys (0 - n) to simulate extra/custom log fields in a log document. + * + * @param numFields Number of fields to generate. + * @param isDegraded If true, will generate fields with more than 1024 characters, and will use a mix of numeric and + * string values to cause mapping conflicts. If false, will generate first half with numeric values and second half with + * string values. + * @param customFieldPrefix Prefix for the field key. Default is 'field'. + */ +function getExtraFields( + numFields: number, + isDegraded = false, + customFieldPrefix = DEFAULT_SCENARIO_OPTS.customFieldPrefix +) { + const extraFields: Record = {}; + for (let i = 0; i < numFields; i++) { + if (isDegraded) { + extraFields[`${customFieldPrefix}-${i}`] = getRandomSlice( + MORE_THAN_1024_CHARS, + MORE_THAN_1024_CHARS.length + ); + } else { + if (i % 2 === 0) { + extraFields[`${customFieldPrefix}-${i}`] = Math.random() * 1000 * 1000; // Assign half of the fields with numeric values + } else { + extraFields[`${customFieldPrefix}-${i}`] = getRandomSlice(MORE_THAN_1024_CHARS, 200); + } + } + } + return extraFields; +} + +/** + * Slices a string from the start index to a random number until length. + */ +function getRandomSlice(str: string, maxLength: number, startIndex = 0) { + const start = Math.min(str.length, startIndex); + const end = Math.min(str.length, start + Math.floor(Math.random() * maxLength)); + return str.slice(start, end); +} + +function killIfUnknownScenarioOptions(logger: Logger, options: Record) { + const unknownOptions = Object.keys(options).filter( + (key) => !Object.keys(DEFAULT_SCENARIO_OPTS).includes(key) + ); + if (unknownOptions.length > 0) { + logger.error(`Unknown scenario option(s): ${unknownOptions.join(', ')}`); + process.exit(1); + } +} + +const NAMESPACES = ['default', 'space-01', 'space-02', 'space-03']; + +const SERVICE_NAMES = [ + 'frontend-rum', + 'azure-functions', + 'frontend', + 'checkout-service', + 'synth-go', + 'synth-node', + 'synth-dotnet', + 'synth-java', + 'productcatalogservice', + 'synth-rum', + 'auditbeat', + 'synth-node-0', + 'payment-service', + 'opbeans-java-otel', + 'packetbeat', + 'cartservice', + 'web-go-0', + 'aws-lambdas', + 'opbeans-go', + 'synth-service-0', + 'synth-service-1', + 'order-processing-dotnet-1', + 'synth-java-0', + 'arn:aws:lambda:us-west-2:001:function:fn-node-2', + 'opbeans-ruby', + 'synth-android', + 'currencyservice', + 'opbeans-python', + 'synth-ios', + 'shippingservice', + 'adservice', + 'recommendationservice', + 'frauddetectionservice', + 'paymentservice', + 'checkoutservice', + 'emailservice', + 'quoteservice', +]; + +const HOSTS = [ + 'apache-integrations-557cfb8fcb-6kb65', + 'mysql-integrations-6b69cc89b4-fzhvw', + 'docker-integrations-6cf69b8966-mnccd', + 'siem-linux-edge-lite-oblt', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-wrzm', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-vvnh', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-tc5h', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-rc92', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-mlgl', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-l7r5', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-js5d', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-f4q6', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-ddlj', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-d18l', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-9m5v', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-7jvw', + 'gke-edge-lite-oblt-edge-lite-oblt-poo-0d6e31aa-475z', +]; + +const CLUSTERS = [ + { clusterId: generateShortId(), clusterName: 'synth-cluster-1' }, + { clusterId: generateShortId(), clusterName: 'synth-cluster-2' }, + { clusterId: generateShortId(), clusterName: 'synth-cluster-3' }, +]; +const CLOUD_PROVIDERS = ['gcp', 'aws', 'azure']; +const CLOUD_REGION = ['eu-central-1', 'us-east-1', 'area-51']; +const AGENTS = [ + { id: 'go-id', name: 'go' }, + { id: 'rum-js-id', name: 'rum-js' }, + { id: 'nodejs-id', name: 'nodejs' }, + { id: 'opbeans-java-id', name: 'opbeans-java' }, + { id: 'opbeans-node-id', name: 'opbeans-node' }, + { id: 'opbeans-python-id', name: 'opbeans-python' }, + { id: 'opbeans-ruby-id', name: 'opbeans-ruby' }, + { id: 'opbeans-dotnet-id', name: 'opbeans-dotnet' }, + { id: 'synth-agent-id', name: 'synth-agent' }, +]; + +const TRANSACTION_NAMES = ['GET /synth/customers', 'GET /synth/orders', 'GET /synth/articles']; + +const DATASETS = [ + 'apache.access', + 'apache.error', + 'nginx.access', + 'nginx.error', + 'apm.access', + 'apm.error', + 'apm.metrics', + 'mysql.access', + 'mysql.error', + 'kubernetes.audit_logs', + 'kubernetes.container_logs', + 'system.syslog', + 'postgresql.error', + 'postgresql.log', + 'redis.error', + 'redis.log', + 'mongodb.error', + 'mongodb.log', + 'activemq.audit', + 'activemq.log', + 'elasticsearch.audit', + 'elasticsearch.slowlog', + 'akamai.siem', + 'auditd.log', + 'auditd_manager.auditd', + 'cloud_security_posture.findings', + 'docker.container_logs', + 'elastic_agent.apm_server', + 'elastic_agent.filebeat', + 'elastic_agent.heartbeat', + 'fleet_server.output_health', + 'fleet_server.logs', + 'kibana.audit', + 'kibana.log', + 'microsoft_sqlserver.audit', + 'microsoft_sqlserver.log', + 'network_traffic.http', + 'network_traffic.dns', + 'apm.logs', + 'apm.traces', + 'apm.rum', + 'apm.profiling', + 'apm.uptime', + 'apm.synthetics', + 'apm.infra', + 'apm.sourcemap', + 'apm.span', + 'apm.transaction', + 'synth.1', + 'synth.2', + 'synth.3', +]; + +const LOG_LEVELS = ['info', 'error', 'warn', 'debug']; + +const MORE_THAN_1024_CHARS = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?'; From 328187b4f86b237056d60e5452b0f6830069dd76 Mon Sep 17 00:00:00 2001 From: Vadim Kibana <82822460+vadimkibana@users.noreply.github.com> Date: Wed, 19 Jun 2024 14:17:24 +0200 Subject: [PATCH 091/123] [ES|QL] AST and `Walker` support for ES|QL params (#186410) ## Summary Closes https://github.com/elastic/kibana/issues/186305 Adds support for (1) un-named, (2) named, and (3) positional ES|QL parameters. ``` ROW unnamed = ?, named = ?named, positional = ?1 ``` - Adds AST node generation. - Adds `Walker`, with support to walk through the parameters. - `Walker.params(ast)` collects all params into an array. #### AST node interface The AST nodes follow the existing "literal" type pattern, which has `type` and `literalTypes` fields. Un-named param `?` AST nodes: ```ts { type: 'literal', literalType: 'param', paramType: 'unnamed', } ``` Named param `?name` AST nodes: ```ts { type: 'literal', literalType: 'param', paramType: 'named', value: 'name', } ``` Positional param `?123` AST nodes: ```ts { type: 'literal', literalType: 'param', paramType: 'positional', value: 123, } ``` ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- packages/kbn-esql-ast/index.ts | 2 + .../src/__tests__/ast_parser.params.test.ts | 176 ++++++++++++++++++ packages/kbn-esql-ast/src/ast_helpers.ts | 2 + packages/kbn-esql-ast/src/ast_walker.ts | 57 ++++++ packages/kbn-esql-ast/src/types.ts | 40 +++- packages/kbn-esql-ast/src/walker/index.ts | 9 + .../kbn-esql-ast/src/walker/walker.test.ts | 69 +++++++ packages/kbn-esql-ast/src/walker/walker.ts | 128 +++++++++++++ .../src/definitions/functions.ts | 4 +- .../src/definitions/options.ts | 2 +- .../src/validation/validation.ts | 2 +- 11 files changed, 486 insertions(+), 5 deletions(-) create mode 100644 packages/kbn-esql-ast/src/__tests__/ast_parser.params.test.ts create mode 100644 packages/kbn-esql-ast/src/walker/index.ts create mode 100644 packages/kbn-esql-ast/src/walker/walker.test.ts create mode 100644 packages/kbn-esql-ast/src/walker/walker.ts diff --git a/packages/kbn-esql-ast/index.ts b/packages/kbn-esql-ast/index.ts index 4f93614ffa4878..c418110ccab873 100644 --- a/packages/kbn-esql-ast/index.ts +++ b/packages/kbn-esql-ast/index.ts @@ -37,3 +37,5 @@ export { getParser, getLexer, ROOT_STATEMENT } from './src/antlr_facade'; export { getAstAndSyntaxErrors } from './src/ast_parser'; export { ESQLErrorListener } from './src/antlr_error_listener'; + +export { Walker, type WalkerOptions, walk } from './src/walker'; diff --git a/packages/kbn-esql-ast/src/__tests__/ast_parser.params.test.ts b/packages/kbn-esql-ast/src/__tests__/ast_parser.params.test.ts new file mode 100644 index 00000000000000..f69412a053e024 --- /dev/null +++ b/packages/kbn-esql-ast/src/__tests__/ast_parser.params.test.ts @@ -0,0 +1,176 @@ +/* + * 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 { getAstAndSyntaxErrors as parse } from '../ast_parser'; +import { Walker } from '../walker'; + +/** + * Un-named parameters are represented by a question mark "?". + */ +describe('un-named parameters', () => { + describe('correctly formatted', () => { + it('can parse a single un-named param', () => { + const query = 'ROW x = ?'; + const { ast, errors } = parse(query); + const params = Walker.params(ast); + + expect(errors.length).toBe(0); + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'unnamed', + location: { + min: 8, + max: 8, + }, + }, + ]); + + const { min, max } = params[0].location; + + expect(query.slice(min, max + 1)).toBe('?'); + }); + }); +}); + +/** + * Positional parameters are represented by a question mark followed by a number "?1". + */ +describe('positional parameters', () => { + describe('correctly formatted', () => { + it('can parse a single positional param', () => { + const query = 'ROW x = ?1'; + const { ast, errors } = parse(query); + const params = Walker.params(ast); + + expect(errors.length).toBe(0); + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: 1, + location: { + min: 8, + max: 9, + }, + }, + ]); + + const { min, max } = params[0].location; + + expect(query.slice(min, max + 1)).toBe('?1'); + }); + + it('multiple positional params', () => { + const query = 'ROW x = ?5, x2 = ?5, y = ?6, z = ?7'; + const { ast, errors } = parse(query); + const params = Walker.params(ast); + + expect(errors.length).toBe(0); + expect(params.length).toBe(4); + params.sort((a, b) => a.location.min - b.location.min); + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: 5, + }, + { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: 5, + }, + { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: 6, + }, + { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: 7, + }, + ]); + }); + }); +}); + +/** + * Named parameters are represented by a question mark followed by a name "?name". + */ +describe('named parameters', () => { + describe('correctly formatted', () => { + it('can parse a single named param', () => { + const query = 'ROW x = ?theName'; + const { ast, errors } = parse(query); + const params = Walker.params(ast); + + expect(errors.length).toBe(0); + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'theName', + location: { + min: 8, + max: 15, + }, + }, + ]); + + const { min, max } = params[0].location; + + expect(query.slice(min, max + 1)).toBe('?theName'); + }); + }); + + it('multiple named params', () => { + const query = 'ROW x = ?a, y = ?b, z = ?c'; + const { ast, errors } = parse(query); + const params = Walker.params(ast); + + expect(errors.length).toBe(0); + expect(params.length).toBe(3); + params.sort((a, b) => a.location.min - b.location.min); + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'a', + }, + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'b', + }, + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'c', + }, + ]); + }); + + describe('when incorrectly formatted, returns errors', () => { + it('two question marks "?" in a row', () => { + const text = 'ROW x = ??'; + const { errors } = parse(text); + expect(errors.length > 0).toBe(true); + }); + }); +}); diff --git a/packages/kbn-esql-ast/src/ast_helpers.ts b/packages/kbn-esql-ast/src/ast_helpers.ts index 69ea76c091146e..76e130f2338077 100644 --- a/packages/kbn-esql-ast/src/ast_helpers.ts +++ b/packages/kbn-esql-ast/src/ast_helpers.ts @@ -163,6 +163,8 @@ export function createLiteral( literalType: type, value: Number(text), }; + } else if (type === 'param') { + throw new Error('Should never happen'); } return { ...partialLiteral, diff --git a/packages/kbn-esql-ast/src/ast_walker.ts b/packages/kbn-esql-ast/src/ast_walker.ts index fc47227a0b0ed8..8584f65bac2b1a 100644 --- a/packages/kbn-esql-ast/src/ast_walker.ts +++ b/packages/kbn-esql-ast/src/ast_walker.ts @@ -15,6 +15,7 @@ import { BooleanDefaultContext, type BooleanExpressionContext, BooleanLiteralContext, + InputParamsContext, BooleanValueContext, type CommandOptionsContext, ComparisonContext, @@ -58,6 +59,8 @@ import { ValueExpressionDefaultContext, IndexIdentifierContext, InlineCastContext, + InputNamedOrPositionalParamContext, + InputParamContext, } from './antlr/esql_parser'; import { createSource, @@ -88,6 +91,9 @@ import type { ESQLCommandOption, ESQLAstItem, ESQLInlineCast, + ESQLUnnamedParamLiteral, + ESQLPositionalParamLiteral, + ESQLNamedParamLiteral, } from './types'; export function collectAllSourceIdentifiers(ctx: FromCommandContext): ESQLAstItem[] { @@ -338,6 +344,57 @@ function getConstant(ctx: ConstantContext): ESQLAstItem { } return createList(ctx, values); } + if (ctx instanceof InputParamsContext && ctx.children) { + const values: ESQLLiteral[] = []; + + for (const child of ctx.children) { + if (child instanceof InputParamContext) { + const literal: ESQLUnnamedParamLiteral = { + type: 'literal', + literalType: 'param', + paramType: 'unnamed', + text: ctx.getText(), + name: '', + location: getPosition(ctx.start, ctx.stop), + incomplete: Boolean(ctx.exception), + }; + values.push(literal); + } else if (child instanceof InputNamedOrPositionalParamContext) { + const text = child.getText(); + const value = text.slice(1); + const valueAsNumber = Number(value); + const isPositional = String(valueAsNumber) === value; + + if (isPositional) { + const literal: ESQLPositionalParamLiteral = { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: valueAsNumber, + text, + name: '', + location: getPosition(ctx.start, ctx.stop), + incomplete: Boolean(ctx.exception), + }; + values.push(literal); + } else { + const literal: ESQLNamedParamLiteral = { + type: 'literal', + literalType: 'param', + paramType: 'named', + value, + text, + name: '', + location: getPosition(ctx.start, ctx.stop), + incomplete: Boolean(ctx.exception), + }; + values.push(literal); + } + } + } + + return values; + } return createUnknownItem(ctx); } diff --git a/packages/kbn-esql-ast/src/types.ts b/packages/kbn-esql-ast/src/types.ts index 22a53d6368d9d5..ebea0aeeb89f0a 100644 --- a/packages/kbn-esql-ast/src/types.ts +++ b/packages/kbn-esql-ast/src/types.ts @@ -10,6 +10,8 @@ export type ESQLAst = ESQLAstCommand[]; export type ESQLAstCommand = ESQLCommand | ESQLAstMetricsCommand; +export type ESQLAstNode = ESQLAstCommand | ESQLAstItem; + export type ESQLSingleAstItem = | ESQLFunction | ESQLCommandOption @@ -22,6 +24,8 @@ export type ESQLSingleAstItem = | ESQLInlineCast | ESQLUnknownItem; +export type ESQLAstField = ESQLFunction | ESQLColumn; + export type ESQLAstItem = ESQLSingleAstItem | ESQLAstItem[]; export interface ESQLLocation { @@ -107,7 +111,8 @@ export type ESQLLiteral = | ESQLNumberLiteral | ESQLBooleanLiteral | ESQLNullLiteral - | ESQLStringLiteral; + | ESQLStringLiteral + | ESQLParamLiteral; // @internal export interface ESQLNumberLiteral extends ESQLAstBaseItem { @@ -137,6 +142,39 @@ export interface ESQLStringLiteral extends ESQLAstBaseItem { value: string; } +// @internal +export interface ESQLParamLiteral extends ESQLAstBaseItem { + type: 'literal'; + literalType: 'param'; + paramType: ParamType; + value?: string | number; +} + +/** + * *Unnamed* parameter is not named, just a question mark "?". + * + * @internal + */ +export type ESQLUnnamedParamLiteral = ESQLParamLiteral<'unnamed'>; + +/** + * *Named* parameter is a question mark followed by a name "?name". + * + * @internal + */ +export interface ESQLNamedParamLiteral extends ESQLParamLiteral<'named'> { + value: string; +} + +/** + * *Positional* parameter is a question mark followed by a number "?1". + * + * @internal + */ +export interface ESQLPositionalParamLiteral extends ESQLParamLiteral<'positional'> { + value: number; +} + export interface ESQLMessage { type: 'error' | 'warning'; text: string; diff --git a/packages/kbn-esql-ast/src/walker/index.ts b/packages/kbn-esql-ast/src/walker/index.ts new file mode 100644 index 00000000000000..5dea00bed0f8a7 --- /dev/null +++ b/packages/kbn-esql-ast/src/walker/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { Walker, type WalkerOptions, walk } from './walker'; diff --git a/packages/kbn-esql-ast/src/walker/walker.test.ts b/packages/kbn-esql-ast/src/walker/walker.test.ts new file mode 100644 index 00000000000000..11c8a141080d5e --- /dev/null +++ b/packages/kbn-esql-ast/src/walker/walker.test.ts @@ -0,0 +1,69 @@ +/* + * 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 { ESQLColumn, ESQLLiteral, getAstAndSyntaxErrors } from '../..'; +import { walk, Walker } from './walker'; + +test('can walk all functions', () => { + const { ast } = getAstAndSyntaxErrors('METRICS index a(b(c(foo)))'); + const functions: string[] = []; + + walk(ast, { + visitFunction: (fn) => functions.push(fn.name), + }); + + expect(functions.sort()).toStrictEqual(['a', 'b', 'c']); +}); + +test('can walk "columns"', () => { + const query = 'ROW x = 1'; + const { ast } = getAstAndSyntaxErrors(query); + const columns: ESQLColumn[] = []; + + walk(ast, { + visitColumn: (node) => columns.push(node), + }); + + expect(columns).toMatchObject([ + { + type: 'column', + name: 'x', + }, + ]); +}); + +test('can walk literals', () => { + const query = 'ROW x = 1'; + const { ast } = getAstAndSyntaxErrors(query); + const columns: ESQLLiteral[] = []; + + walk(ast, { + visitLiteral: (node) => columns.push(node), + }); + + expect(columns).toMatchObject([ + { + type: 'literal', + name: '1', + }, + ]); +}); + +test('can collect all params', () => { + const query = 'ROW x = ?'; + const { ast } = getAstAndSyntaxErrors(query); + const params = Walker.params(ast); + + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'unnamed', + }, + ]); +}); diff --git a/packages/kbn-esql-ast/src/walker/walker.ts b/packages/kbn-esql-ast/src/walker/walker.ts new file mode 100644 index 00000000000000..8ebf6911599d4f --- /dev/null +++ b/packages/kbn-esql-ast/src/walker/walker.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { + ESQLAstCommand, + ESQLAstItem, + ESQLAstNode, + ESQLColumn, + ESQLFunction, + ESQLLiteral, + ESQLParamLiteral, + ESQLSingleAstItem, +} from '../types'; + +export interface WalkerOptions { + visitSingleAstItem?: (node: ESQLSingleAstItem) => void; + visitFunction?: (node: ESQLFunction) => void; + visitColumn?: (node: ESQLColumn) => void; + visitLiteral?: (node: ESQLLiteral) => void; +} + +export class Walker { + /** + * Walks the AST and calls the appropriate visitor functions. + */ + public static readonly walk = ( + node: ESQLAstNode | ESQLAstNode[], + options: WalkerOptions + ): Walker => { + const walker = new Walker(options); + walker.walk(node); + return walker; + }; + + /** + * Walks the AST and extracts all parameter literals. + * + * @param node AST node to extract parameters from. + */ + public static readonly params = (node: ESQLAstNode | ESQLAstNode[]): ESQLParamLiteral[] => { + const params: ESQLParamLiteral[] = []; + Walker.walk(node, { + visitLiteral: (param) => { + if (param.literalType === 'param') { + params.push(param); + } + }, + }); + return params; + }; + + constructor(protected readonly options: WalkerOptions) {} + + public walk(node: undefined | ESQLAstNode | ESQLAstNode[]): void { + if (!node) return; + + if (node instanceof Array) { + for (const item of node) this.walk(item); + return; + } + + switch (node.type) { + case 'command': { + this.walkCommand(node as ESQLAstCommand); + break; + } + default: { + this.walkAstItem(node as ESQLAstItem); + break; + } + } + } + + public walkCommand(node: ESQLAstCommand): void { + switch (node.name) { + default: { + this.walk(node.args); + break; + } + } + } + + public walkAstItem(node: ESQLAstItem): void { + if (node instanceof Array) { + const list = node as ESQLAstItem[]; + for (const item of list) this.walkAstItem(item); + } else { + const item = node as ESQLSingleAstItem; + this.walkSingleAstItem(item); + } + } + + public walkSingleAstItem(node: ESQLSingleAstItem): void { + const { options } = this; + options.visitSingleAstItem?.(node); + switch (node.type) { + case 'function': { + this.walkFunction(node as ESQLFunction); + break; + } + case 'column': { + options.visitColumn?.(node); + break; + } + case 'literal': { + options.visitLiteral?.(node); + break; + } + } + } + + public walkFunction(node: ESQLFunction): void { + this.options.visitFunction?.(node); + const args = node.args; + const length = args.length; + for (let i = 0; i < length; i++) { + const arg = args[i]; + this.walkAstItem(arg); + } + } +} + +export const walk = Walker.walk; diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/functions.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/functions.ts index 77f4195f15a829..6c96111b74d9e1 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/functions.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/functions.ts @@ -1345,7 +1345,7 @@ const logDefinition: FunctionDefinition = { // do not really care here about the base and field // just need to check both values are not negative for (const arg of fnDef.args) { - if (isLiteralItem(arg) && arg.value < 0) { + if (isLiteralItem(arg) && Number(arg.value) < 0) { messages.push({ type: 'warning' as const, code: 'logOfNegativeValue', @@ -1398,7 +1398,7 @@ const log10Definition: FunctionDefinition = { // do not really care here about the base and field // just need to check both values are not negative for (const arg of fnDef.args) { - if (isLiteralItem(arg) && arg.value < 0) { + if (isLiteralItem(arg) && Number(arg.value) < 0) { messages.push({ type: 'warning' as const, code: 'logOfNegativeValue', diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts index 13e3ea66ef1063..cd81ae3096e54b 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/options.ts @@ -135,7 +135,7 @@ export const appendSeparatorOption: CommandOptionsDefinition = { messages.push( getMessageFromId({ messageId: 'wrongDissectOptionArgumentType', - values: { value }, + values: { value: value ?? '' }, locations: firstArg.location, }) ); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts index 438d1fd826d00f..a0c2d385c3e990 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -109,7 +109,7 @@ function validateFunctionLiteralArg( values: { name: astFunction.name, argType: argDef.type, - value: actualArg.value, + value: typeof actualArg.value === 'number' ? actualArg.value : String(actualArg.value), givenType: actualArg.literalType, }, locations: actualArg.location, From c0b65d605ce03847336f393912688a8998b9cb6e Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Wed, 19 Jun 2024 09:04:48 -0400 Subject: [PATCH 092/123] feat(slo): group by instance id (#186131) --- .../src/rest_specs/routes/find_group.ts | 1 + .../kbn-slo-schema/src/schema/common.ts | 1 + .../grouped_slos/group_list_view.tsx | 23 +----- .../grouped_slos/group_view.test.tsx | 56 +++++++++++++- .../grouped_slos/hooks/use_group_name.test.ts | 76 +++++++++++++++++++ .../grouped_slos/hooks/use_group_name.ts | 67 ++++++++++++++++ .../slos/components/slo_list_group_by.tsx | 18 ++++- .../slo/server/services/find_slo_groups.ts | 10 ++- 8 files changed, 225 insertions(+), 27 deletions(-) create mode 100644 x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.test.ts create mode 100644 x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.ts diff --git a/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find_group.ts b/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find_group.ts index 3c04134c833128..7c3f5e576cea50 100644 --- a/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find_group.ts +++ b/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find_group.ts @@ -12,6 +12,7 @@ const groupBySchema = t.union([ t.literal('slo.tags'), t.literal('status'), t.literal('slo.indicator.type'), + t.literal('slo.instanceId'), t.literal('_index'), ]); diff --git a/x-pack/packages/kbn-slo-schema/src/schema/common.ts b/x-pack/packages/kbn-slo-schema/src/schema/common.ts index 188a5b8f072666..ff30ae5f254838 100644 --- a/x-pack/packages/kbn-slo-schema/src/schema/common.ts +++ b/x-pack/packages/kbn-slo-schema/src/schema/common.ts @@ -81,6 +81,7 @@ const groupSummarySchema = t.type({ id: t.string, instanceId: t.string, name: t.string, + groupings: t.record(t.string, t.unknown), }), }), violated: t.number, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_list_view.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_list_view.tsx index eefe5c1ba1e878..cee082338d78c3 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_list_view.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_list_view.tsx @@ -27,12 +27,12 @@ import React, { memo, useState } from 'react'; import { paths } from '../../../../../common/locators/paths'; import { useFetchSloList } from '../../../../hooks/use_fetch_slo_list'; import { useKibana } from '../../../../utils/kibana_react'; -import { SLI_OPTIONS } from '../../../slo_edit/constants'; import { useSloFormattedSLIValue } from '../../hooks/use_slo_summary'; import type { SortDirection, SortField } from '../../hooks/use_url_search_state'; import { SlosView } from '../slos_view'; import { GroupByField } from '../slo_list_group_by'; import { SLOView } from '../toggle_slo_view'; +import { useGroupName } from './hooks/use_group_name'; interface Props { group: string; @@ -57,26 +57,7 @@ export function GroupListView({ }: Props) { const groupQuery = `"${groupBy}": "${group}"`; const query = kqlQuery ? `${groupQuery} and ${kqlQuery}` : groupQuery; - let groupName = group.toLowerCase(); - if (groupBy === 'slo.indicator.type') { - groupName = SLI_OPTIONS.find((option) => option.value === group)?.text ?? group; - } - if (groupBy === '_index') { - // get remote cluster name from index name - if (groupName.includes(':.')) { - const [remoteClusterName] = groupName.split(':.'); - groupName = i18n.translate('xpack.slo.group.remoteCluster', { - defaultMessage: 'Remote Cluster: {remoteClusterName}', - values: { - remoteClusterName, - }, - }); - } else { - groupName = i18n.translate('xpack.slo.group.remoteCluster.localKibana', { - defaultMessage: 'Local Kibana', - }); - } - } + const groupName = useGroupName(groupBy, group, summary); const [page, setPage] = useState(0); const [accordionState, setAccordionState] = useState<'open' | 'closed'>('closed'); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_view.test.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_view.test.tsx index 3c61534d479b7b..775659f6be5805 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_view.test.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_view.test.tsx @@ -105,17 +105,65 @@ describe('Group View', () => { { group: 'production', groupBy: 'slo.tags', - summary: { total: 3, worst: 0.95, healthy: 2, violated: 1, degrading: 0, noData: 0 }, + summary: { + total: 3, + worst: { + sliValue: 1, + status: 'healthy', + slo: { + id: 'irrelevant', + instanceId: 'irrelevant', + name: 'irrelevant', + groupings: {}, + }, + }, + healthy: 2, + violated: 1, + degrading: 0, + noData: 0, + }, }, { group: 'something', groupBy: 'slo.tags', - summary: { total: 1, worst: 0.9, healthy: 0, violated: 1, degrading: 0, noData: 0 }, + summary: { + total: 1, + worst: { + sliValue: 1, + status: 'healthy', + slo: { + id: 'irrelevant', + instanceId: 'irrelevant', + name: 'irrelevant', + groupings: {}, + }, + }, + healthy: 0, + violated: 1, + degrading: 0, + noData: 0, + }, }, { group: 'anything', groupBy: 'slo.tags', - summary: { total: 2, worst: 0.85, healthy: 1, violated: 0, degrading: 0, noData: 1 }, + summary: { + total: 2, + worst: { + sliValue: 1, + status: 'healthy', + slo: { + id: 'irrelevant', + instanceId: 'irrelevant', + name: 'irrelevant', + groupings: {}, + }, + }, + healthy: 1, + violated: 0, + degrading: 0, + noData: 1, + }, }, ], }, @@ -163,7 +211,7 @@ describe('Group View', () => { results: [ { group: 'production', - groupBy: 'tags', + groupBy: 'slo.tags', summary: { total: 3, worst: 0.95, healthy: 2, violated: 1, degrading: 0, noData: 0 }, }, ], diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.test.ts b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.test.ts new file mode 100644 index 00000000000000..fa2b5192665ea7 --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SLO_SUMMARY_DESTINATION_INDEX_PATTERN } from '../../../../../../common/constants'; +import { GroupSummary } from '@kbn/slo-schema'; +import { useGroupName } from './use_group_name'; + +describe('useGroupName', () => { + it('returns the group name for ungrouped', () => { + const groupName = useGroupName('ungrouped', 'irrelevant', {} as GroupSummary); + expect(groupName).toBe('irrelevant'); + }); + + it('returns the group name for slo tags', () => { + const groupName = useGroupName('slo.tags', 'some-tag', {} as GroupSummary); + expect(groupName).toBe('some-tag'); + }); + + it('returns the group name for status', () => { + const groupName = useGroupName('status', 'HEALTHY', {} as GroupSummary); + expect(groupName).toBe('healthy'); + }); + + it('returns the group name for slo instanceId', () => { + const summary = { + total: 2, + violated: 0, + healthy: 2, + degrading: 0, + noData: 0, + worst: { + sliValue: 1, + status: 'healthy', + slo: { + id: 'slo-id', + name: 'slo-name', + instanceId: 'domain.com', + groupings: { + host: { + name: 'domain.com', + }, + }, + }, + }, + } as GroupSummary; + const groupName = useGroupName('slo.instanceId', 'domain.com', summary); + expect(groupName).toBe('host.name: domain.com'); + }); + + it('returns the group name for slo indicator type', () => { + const groupName = useGroupName('slo.indicator.type', 'sli.kql.custom', {} as GroupSummary); + expect(groupName).toBe('Custom Query'); + }); + + it('returns the group name for local index', () => { + const groupName = useGroupName( + '_index', + SLO_SUMMARY_DESTINATION_INDEX_PATTERN, + {} as GroupSummary + ); + expect(groupName).toBe('Local Kibana'); + }); + + it('returns the group name for remote index', () => { + const groupName = useGroupName( + '_index', + `my-remote-cluster:${SLO_SUMMARY_DESTINATION_INDEX_PATTERN}`, + {} as GroupSummary + ); + expect(groupName).toBe('Remote Cluster: my-remote-cluster'); + }); +}); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.ts b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.ts new file mode 100644 index 00000000000000..ca6ddff88fb19f --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/hooks/use_group_name.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { ALL_VALUE, GroupSummary } from '@kbn/slo-schema'; +import { assertNever } from '@kbn/std'; +import { SLI_OPTIONS } from '../../../../slo_edit/constants'; +import { GroupByField } from '../../slo_list_group_by'; + +export function useGroupName(groupBy: GroupByField, group: string, summary?: GroupSummary) { + const groupName = group.toLowerCase(); + + switch (groupBy) { + case 'ungrouped': + case 'slo.tags': + case 'status': + return groupName; + case 'slo.instanceId': + if (groupName === ALL_VALUE || !summary) { + return i18n.translate('xpack.slo.group.ungroupedInstanceId', { + defaultMessage: 'Ungrouped', + }); + } + + const groupNames = flattenObject(summary.worst.slo.groupings); + return Object.entries(groupNames) + .map(([key, value]) => `${key}: ${value}`) + .join(', '); + case 'slo.indicator.type': + return SLI_OPTIONS.find((option) => option.value === group)?.text ?? groupName; + case '_index': + if (groupName.includes(':.')) { + const [remoteClusterName] = groupName.split(':.'); + return i18n.translate('xpack.slo.group.remoteCluster', { + defaultMessage: 'Remote Cluster: {remoteClusterName}', + values: { + remoteClusterName, + }, + }); + } + + return i18n.translate('xpack.slo.group.remoteCluster.localKibana', { + defaultMessage: 'Local Kibana', + }); + + default: + assertNever(groupBy); + } +} + +function flattenObject(obj: Record, parentKey = '', result: Record = {}) { + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + const newKey = parentKey ? `${parentKey}.${key}` : key; + if (typeof obj[key] === 'object' && obj[key] !== null) { + flattenObject(obj[key], newKey, result); + } else { + result[newKey] = obj[key]; + } + } + } + return result; +} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_list_group_by.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_list_group_by.tsx index b2764a4b9ab197..d7175553fd1783 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_list_group_by.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_list_group_by.tsx @@ -13,7 +13,13 @@ import type { SearchState } from '../hooks/use_url_search_state'; import type { Option } from './slo_context_menu'; import { ContextMenuItem, SLOContextMenu } from './slo_context_menu'; -export type GroupByField = 'ungrouped' | 'slo.tags' | 'status' | 'slo.indicator.type' | '_index'; +export type GroupByField = + | 'ungrouped' + | 'slo.tags' + | 'status' + | 'slo.indicator.type' + | 'slo.instanceId' + | '_index'; export interface Props { onStateChange: (newState: Partial) => void; state: SearchState; @@ -80,6 +86,16 @@ export function SloGroupBy({ onStateChange, state, loading }: Props) { handleChangeGroupBy('slo.indicator.type'); }, }, + { + label: i18n.translate('xpack.slo.list.groupBy.sloInstanceId', { + defaultMessage: 'SLO instance id', + }), + checked: groupBy === 'slo.instanceId', + value: 'slo.instanceId', + onClick: () => { + handleChangeGroupBy('slo.instanceId'); + }, + }, ]; if (hasRemoteEnabled) { diff --git a/x-pack/plugins/observability_solution/slo/server/services/find_slo_groups.ts b/x-pack/plugins/observability_solution/slo/server/services/find_slo_groups.ts index c3fadc6f60ba0c..7282f276ea572a 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/find_slo_groups.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/find_slo_groups.ts @@ -87,7 +87,14 @@ export class FindSLOGroups { }, }, _source: { - includes: ['sliValue', 'status', 'slo.id', 'slo.instanceId', 'slo.name'], + includes: [ + 'sliValue', + 'status', + 'slo.id', + 'slo.instanceId', + 'slo.name', + 'slo.groupings', + ], }, size: 1, }, @@ -165,6 +172,7 @@ export class FindSLOGroups { id: sourceSummaryDoc.slo.id, instanceId: sourceSummaryDoc.slo.instanceId, name: sourceSummaryDoc.slo.name, + groupings: sourceSummaryDoc.slo.groupings, }, }, violated: bucket.violated?.doc_count, From 05723d4775347cc31cfbe4693bbb504fe25324b5 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 19 Jun 2024 15:31:44 +0200 Subject: [PATCH 093/123] [Discover][DocViewer] Convert EuiTable to EuiDataGrid. Enable up to 500 fields per page. (#175787) - Closes https://github.com/elastic/kibana/issues/174745 ## Summary This PR converts Doc Viewer table into EuiDataGrid to use its actions functionality. Screenshot 2024-05-17 at 20 18 44 Screenshot 2024-05-17 at 18 17 49 Screenshot 2024-05-17 at 18 18 05 Screenshot 2024-05-22 at 15 22 31 ## Testing Some cases to check while testing: - varios value formats - legacy table vs data grid - doc viewer flyout vs Single Document page ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Andrea Del Rio Co-authored-by: Davis McPhee Co-authored-by: Stratoula Kalafateli Co-authored-by: Davis McPhee --- packages/kbn-field-utils/index.ts | 4 - .../field_description_icon_button.test.tsx | 34 -- .../field_description_icon_button.tsx | 60 --- .../components/doc_viewer/doc_viewer_tab.tsx | 2 + .../__snapshots__/field_name.test.tsx.snap | 419 +++++++++------- .../src/components/field_name/field_name.scss | 12 +- .../src/components/field_name/field_name.tsx | 123 +++-- .../src/services/types.ts | 3 +- .../discover_internal_state_container.ts | 3 + .../discover_grid_flyout.test.tsx | 20 +- .../discover_grid_flyout.tsx | 257 ++-------- .../doc_table/components/table_row.test.tsx | 8 +- .../components/table_row_details.tsx | 2 +- .../context_awareness/__mocks__/index.ts | 2 +- .../public/context_awareness/types.ts | 2 +- src/plugins/discover/public/index.ts | 1 - .../esql_datagrid/public/data_grid.tsx | 2 +- .../esql_datagrid/public/row_viewer.test.tsx | 8 +- .../esql_datagrid/public/row_viewer.tsx | 207 +------- src/plugins/esql_datagrid/tsconfig.json | 3 +- .../doc_viewer_flyout/doc_viewer_flyout.tsx | 311 ++++++++++++ .../components/doc_viewer_flyout}/index.ts | 9 +- .../doc_viewer_source/get_height.test.tsx | 16 +- .../doc_viewer_source/get_height.tsx | 28 +- .../components/doc_viewer_source/source.tsx | 14 +- .../table_cell_actions.test.tsx.snap | 351 +++++++++++++ .../doc_viewer_table/legacy/table.tsx | 16 +- .../legacy/table_cell_actions.tsx | 14 +- .../components/doc_viewer_table/table.scss | 23 + .../components/doc_viewer_table/table.tsx | 434 +++++++++-------- .../table_cell_actions.test.tsx | 118 +++-- .../doc_viewer_table/table_cell_actions.tsx | 460 ++++++++++-------- .../public/components/index.ts | 1 + .../public/components/lazy_doc_viewer.tsx | 20 + .../components/lazy_doc_viewer_flyout.tsx | 17 + .../unified_doc_viewer/public/index.tsx | 11 +- .../unified_doc_viewer/public/plugin.tsx | 3 +- src/plugins/unified_doc_viewer/tsconfig.json | 4 +- test/accessibility/apps/discover.ts | 10 +- test/functional/apps/context/_filters.ts | 3 +- .../dashboard/group1/embeddable_data_grid.ts | 2 +- .../dashboard/group1/url_field_formatter.ts | 6 +- .../apps/discover/classic/_doc_table.ts | 6 +- .../apps/discover/classic/_esql_grid.ts | 4 +- .../group2_data_grid1/_data_grid_doc_table.ts | 6 +- .../_data_grid_field_tokens.ts | 2 +- .../apps/discover/group3/_doc_viewer.ts | 6 +- .../discover/group7/_runtime_fields_editor.ts | 2 +- test/functional/services/data_grid.ts | 29 +- .../translations/translations/fr-FR.json | 14 +- .../translations/translations/ja-JP.json | 14 +- .../translations/translations/zh-CN.json | 14 +- .../test_suites/common/context/_filters.ts | 3 +- .../discover/group2/_data_grid_doc_table.ts | 6 +- 54 files changed, 1849 insertions(+), 1300 deletions(-) delete mode 100644 packages/kbn-field-utils/src/components/field_description_icon_button/field_description_icon_button.test.tsx delete mode 100644 packages/kbn-field-utils/src/components/field_description_icon_button/field_description_icon_button.tsx create mode 100644 src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/doc_viewer_flyout.tsx rename {packages/kbn-field-utils/src/components/field_description_icon_button => src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout}/index.ts (65%) create mode 100644 src/plugins/unified_doc_viewer/public/components/doc_viewer_table/__snapshots__/table_cell_actions.test.tsx.snap create mode 100644 src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer.tsx create mode 100644 src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer_flyout.tsx diff --git a/packages/kbn-field-utils/index.ts b/packages/kbn-field-utils/index.ts index d631c51c757a4c..3adb2679389405 100644 --- a/packages/kbn-field-utils/index.ts +++ b/packages/kbn-field-utils/index.ts @@ -27,7 +27,3 @@ export { export { FieldIcon, type FieldIconProps, getFieldIconProps } from './src/components/field_icon'; export { FieldDescription, type FieldDescriptionProps } from './src/components/field_description'; -export { - FieldDescriptionIconButton, - type FieldDescriptionIconButtonProps, -} from './src/components/field_description_icon_button'; diff --git a/packages/kbn-field-utils/src/components/field_description_icon_button/field_description_icon_button.test.tsx b/packages/kbn-field-utils/src/components/field_description_icon_button/field_description_icon_button.test.tsx deleted file mode 100644 index c677415cd4ace0..00000000000000 --- a/packages/kbn-field-utils/src/components/field_description_icon_button/field_description_icon_button.test.tsx +++ /dev/null @@ -1,34 +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 React from 'react'; -import { FieldDescriptionIconButton } from './field_description_icon_button'; -import { render, screen } from '@testing-library/react'; - -describe('FieldDescriptionIconButton', () => { - it('should render correctly when no custom description', async () => { - const { container } = render(); - expect(container).toBeEmptyDOMElement(); - }); - - it('should render correctly with a short custom description', async () => { - const customDescription = 'test this desc'; - render(); - expect(screen.queryByTestId('fieldDescription-bytes')).toBeNull(); - screen.queryByTestId('fieldDescriptionPopoverButton-bytes')?.click(); - expect(screen.queryByTestId('fieldDescription-bytes')).toHaveTextContent(customDescription); - }); - - it('should render correctly with a long custom description', async () => { - const customDescription = 'test this long desc '.repeat(8).trim(); - render(); - expect(screen.queryByTestId('fieldDescription-bytes')).toBeNull(); - screen.queryByTestId('fieldDescriptionPopoverButton-bytes')?.click(); - expect(screen.queryByTestId('fieldDescription-bytes')).toHaveTextContent(customDescription); - }); -}); diff --git a/packages/kbn-field-utils/src/components/field_description_icon_button/field_description_icon_button.tsx b/packages/kbn-field-utils/src/components/field_description_icon_button/field_description_icon_button.tsx deleted file mode 100644 index c0358c53cd27f2..00000000000000 --- a/packages/kbn-field-utils/src/components/field_description_icon_button/field_description_icon_button.tsx +++ /dev/null @@ -1,60 +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 React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { css } from '@emotion/react'; -import { EuiButtonIcon, EuiPopover, EuiPopoverProps, useEuiTheme } from '@elastic/eui'; -import { FieldDescription, FieldDescriptionProps } from '../field_description'; - -export type FieldDescriptionIconButtonProps = Pick & { - field: FieldDescriptionProps['field']; -}; - -export const FieldDescriptionIconButton: React.FC = ({ - field, - ...otherProps -}) => { - const { euiTheme } = useEuiTheme(); - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - - if (!field?.customDescription) { - return null; - } - - const buttonTitle = i18n.translate('fieldUtils.fieldDescriptionIconButtonTitle', { - defaultMessage: 'View field description', - }); - - return ( - - setIsPopoverOpen(false)} - panelProps={{ - css: css` - max-width: ${euiTheme.base * 20}px; - `, - }} - button={ - setIsPopoverOpen(!isPopoverOpen)} - /> - } - > - - - - ); -}; diff --git a/packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer_tab.tsx b/packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer_tab.tsx index ad0f7d9461f588..95a4db9528ad2c 100644 --- a/packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer_tab.tsx +++ b/packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer_tab.tsx @@ -46,6 +46,8 @@ export class DocViewerTab extends React.Component { !isEqual(nextProps.renderProps.hit.raw.highlight, this.props.renderProps.hit.raw.highlight) || nextProps.id !== this.props.id || !isEqual(nextProps.renderProps.columns, this.props.renderProps.columns) || + nextProps.renderProps.decreaseAvailableHeightBy !== + this.props.renderProps.decreaseAvailableHeightBy || nextState.hasError ); } diff --git a/packages/kbn-unified-doc-viewer/src/components/field_name/__snapshots__/field_name.test.tsx.snap b/packages/kbn-unified-doc-viewer/src/components/field_name/__snapshots__/field_name.test.tsx.snap index c63b1b5bc0d11d..cf9ddb38bbe69a 100644 --- a/packages/kbn-unified-doc-viewer/src/components/field_name/__snapshots__/field_name.test.tsx.snap +++ b/packages/kbn-unified-doc-viewer/src/components/field_name/__snapshots__/field_name.test.tsx.snap @@ -1,268 +1,349 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`FieldName renders a custom description icon 1`] = ` -Array [ +
- - - String - - -
, -
- - - test + + + String + - +
+
+
- -
+ - -
-
+ + test + + +
-
, -] +
+
`; exports[`FieldName renders a geo field 1`] = ` -Array [ +
- - - Geo point - - -
, + + + Geo point + + +
+ +
- - - test.test.test + + + test.test.test + - +
- , -] + + `; exports[`FieldName renders a number field by providing a field record 1`] = ` -Array [ +
- - - Number - - -
, + + + Number + + +
+ +
- - - test.test.test + + + test.test.test + - +
- , -] + + `; exports[`FieldName renders a string field by providing fieldType and fieldName 1`] = ` -Array [ +
- - - String - - -
, + + + String + + +
+ +
- - - test + + + test + - +
- , -] + + `; exports[`FieldName renders unknown field 1`] = ` -Array [ +
- - - Unknown field - - -
, + + + Unknown field + + +
+ +
- - - test.test.test + + + test.test.test + - +
- , -] + + `; exports[`FieldName renders when mapping is provided 1`] = ` -Array [ +
- - - Number - - -
, + + + Number + + +
+ +
- - - bytes + + + bytes + - +
- , -] + + `; exports[`FieldName renders with a search highlight 1`] = ` -Array [ +
- - - Number - - -
, + + + Number + + +
+ +
- - - - te - - st.test.test + + + + te + + st.test.test + - +
- , -] + + `; diff --git a/packages/kbn-unified-doc-viewer/src/components/field_name/field_name.scss b/packages/kbn-unified-doc-viewer/src/components/field_name/field_name.scss index edc4ea270d7554..fce22a86b8c73f 100644 --- a/packages/kbn-unified-doc-viewer/src/components/field_name/field_name.scss +++ b/packages/kbn-unified-doc-viewer/src/components/field_name/field_name.scss @@ -1,12 +1,20 @@ -.kbnDocViewer__fieldIcon { +.kbnDocViewer__fieldIconContainer { padding-top: $euiSizeXS * 1.5; + line-height: $euiSize; } .kbnDocViewer__fieldName { - line-height: $euiLineHeight; padding: $euiSizeXS; + padding-left: 0; + line-height: $euiLineHeight; + + .euiDataGridRowCell__popover & { + font-size: $euiFontSizeS; + line-height: $euiLineHeight; + } } .kbnDocViewer__multiFieldBadge { @include euiFont; + margin: $euiSizeXS 0; } diff --git a/packages/kbn-unified-doc-viewer/src/components/field_name/field_name.tsx b/packages/kbn-unified-doc-viewer/src/components/field_name/field_name.tsx index 9494cc4d03ae0d..d7f380195947a3 100644 --- a/packages/kbn-unified-doc-viewer/src/components/field_name/field_name.tsx +++ b/packages/kbn-unified-doc-viewer/src/components/field_name/field_name.tsx @@ -6,15 +6,22 @@ * Side Public License, v 1. */ -import React, { Fragment } from 'react'; +import React from 'react'; import './field_name.scss'; -import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiToolTip, EuiHighlight } from '@elastic/eui'; +import { + EuiBadge, + EuiFlexGroup, + EuiFlexItem, + EuiToolTip, + EuiHighlight, + EuiIcon, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { FieldIcon, FieldIconProps } from '@kbn/react-field'; import type { DataViewField } from '@kbn/data-views-plugin/public'; import { getDataViewFieldSubtypeMulti } from '@kbn/es-query'; -import { FieldDescriptionIconButton, getFieldTypeName } from '@kbn/field-utils'; +import { getFieldTypeName } from '@kbn/field-utils'; interface Props { fieldName: string; @@ -23,6 +30,7 @@ interface Props { fieldIconProps?: Omit; scripted?: boolean; highlight?: string; + isPinned?: boolean; } export function FieldName({ @@ -32,6 +40,7 @@ export function FieldName({ fieldIconProps, scripted = false, highlight = '', + isPinned = false, }: Props) { const typeName = getFieldTypeName(fieldType); const displayName = @@ -41,54 +50,76 @@ export function FieldName({ const isMultiField = !!subTypeMulti?.multi; return ( - - - + + + + + + + {isPinned && ( + + + + )} + - - - + + - {displayName} - - - - {fieldMapping?.customDescription ? ( - - + + {displayName} + - ) : null} - {isMultiField && ( - - - - - - )} - - + + + + + )} + + + ); } diff --git a/packages/kbn-unified-doc-viewer/src/services/types.ts b/packages/kbn-unified-doc-viewer/src/services/types.ts index 115583c738bb09..c6e10d09cea007 100644 --- a/packages/kbn-unified-doc-viewer/src/services/types.ts +++ b/packages/kbn-unified-doc-viewer/src/services/types.ts @@ -49,6 +49,7 @@ export interface DocViewRenderProps { onAddColumn?: (columnName: string) => void; onRemoveColumn?: (columnName: string) => void; docViewsRegistry?: DocViewsRegistry | ((prevRegistry: DocViewsRegistry) => DocViewsRegistry); + decreaseAvailableHeightBy?: number; } export type DocViewerComponent = React.FC; export type DocViewRenderFn = ( @@ -83,7 +84,7 @@ export interface FieldRecordLegacy { action: { isActive: boolean; onFilter?: DocViewFilterFn; - onToggleColumn: (field: string) => void; + onToggleColumn: ((field: string) => void) | undefined; flattenedField: unknown; }; field: { diff --git a/src/plugins/discover/public/application/main/state_management/discover_internal_state_container.ts b/src/plugins/discover/public/application/main/state_management/discover_internal_state_container.ts index 4b26822bf04a50..4ebbe94832d0c6 100644 --- a/src/plugins/discover/public/application/main/state_management/discover_internal_state_container.ts +++ b/src/plugins/discover/public/application/main/state_management/discover_internal_state_container.ts @@ -73,6 +73,8 @@ export function getInternalStateContainer() { setDataView: (prevState: InternalState) => (nextDataView: DataView) => ({ ...prevState, dataView: nextDataView, + expandedDoc: + nextDataView?.id !== prevState.dataView?.id ? undefined : prevState.expandedDoc, }), setIsDataViewLoading: (prevState: InternalState) => (loading: boolean) => ({ ...prevState, @@ -130,6 +132,7 @@ export function getInternalStateContainer() { resetOnSavedSearchChange: (prevState: InternalState) => () => ({ ...prevState, overriddenVisContextAfterInvalidation: undefined, + expandedDoc: undefined, }), }, {}, diff --git a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx index 456f10d89dc893..2129610aad3a11 100644 --- a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx +++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx @@ -161,13 +161,13 @@ describe('Discover flyout', function () { it('displays document navigation when there is more than 1 doc available', async () => { const { component } = await mountComponent({ dataView: dataViewWithTimefieldMock }); - const docNav = findTestSubject(component, 'dscDocNavigation'); + const docNav = findTestSubject(component, 'docViewerFlyoutNavigation'); expect(docNav.length).toBeTruthy(); }); it('displays no document navigation when there are 0 docs available', async () => { const { component } = await mountComponent({ records: [], expandedHit: esHitsMock[0] }); - const docNav = findTestSubject(component, 'dscDocNavigation'); + const docNav = findTestSubject(component, 'docViewerFlyoutNavigation'); expect(docNav.length).toBeFalsy(); }); @@ -190,7 +190,7 @@ describe('Discover flyout', function () { }, ].map((hit) => buildDataTableRecord(hit, dataViewMock)); const { component } = await mountComponent({ records, expandedHit: esHitsMock[0] }); - const docNav = findTestSubject(component, 'dscDocNavigation'); + const docNav = findTestSubject(component, 'docViewerFlyoutNavigation'); expect(docNav.length).toBeFalsy(); }); @@ -230,19 +230,19 @@ describe('Discover flyout', function () { it('allows navigating with arrow keys through documents', async () => { const { component, props } = await mountComponent({}); - findTestSubject(component, 'docTableDetailsFlyout').simulate('keydown', { key: 'ArrowRight' }); + findTestSubject(component, 'docViewerFlyout').simulate('keydown', { key: 'ArrowRight' }); expect(props.setExpandedDoc).toHaveBeenCalledWith(expect.objectContaining({ id: 'i::2::' })); component.setProps({ ...props, hit: props.hits[1] }); - findTestSubject(component, 'docTableDetailsFlyout').simulate('keydown', { key: 'ArrowLeft' }); + findTestSubject(component, 'docViewerFlyout').simulate('keydown', { key: 'ArrowLeft' }); expect(props.setExpandedDoc).toHaveBeenCalledWith(expect.objectContaining({ id: 'i::1::' })); }); it('should not navigate with keypresses when already at the border of documents', async () => { const { component, props } = await mountComponent({}); - findTestSubject(component, 'docTableDetailsFlyout').simulate('keydown', { key: 'ArrowLeft' }); + findTestSubject(component, 'docViewerFlyout').simulate('keydown', { key: 'ArrowLeft' }); expect(props.setExpandedDoc).not.toHaveBeenCalled(); component.setProps({ ...props, hit: props.hits[props.hits.length - 1] }); - findTestSubject(component, 'docTableDetailsFlyout').simulate('keydown', { key: 'ArrowRight' }); + findTestSubject(component, 'docViewerFlyout').simulate('keydown', { key: 'ArrowRight' }); expect(props.setExpandedDoc).not.toHaveBeenCalled(); }); @@ -267,7 +267,7 @@ describe('Discover flyout', function () { }); const singleDocumentView = findTestSubject(component, 'docTableRowAction'); expect(singleDocumentView.length).toBeFalsy(); - const flyoutTitle = findTestSubject(component, 'docTableRowDetailsTitle'); + const flyoutTitle = findTestSubject(component, 'docViewerRowDetailsTitle'); expect(flyoutTitle.text()).toBe('Result'); }); @@ -279,7 +279,7 @@ describe('Discover flyout', function () { const { component } = await mountComponent({}); - const titleNode = findTestSubject(component, 'docTableRowDetailsTitle'); + const titleNode = findTestSubject(component, 'docViewerRowDetailsTitle'); expect(titleNode.text()).toBe(customTitle); }); @@ -503,7 +503,7 @@ describe('Discover flyout', function () { processRecord: (record) => services.profilesManager.resolveDocumentProfile({ record }), }); const { component } = await mountComponent({ records, services }); - const title = findTestSubject(component, 'docTableRowDetailsTitle'); + const title = findTestSubject(component, 'docViewerRowDetailsTitle'); expect(title.text()).toBe('Document #new::1::'); const content = findTestSubject(component, 'kbnDocViewer'); expect(content.text()).toBe('Mock tab'); diff --git a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx index 891ae384bd41a5..778d05435e709e 100644 --- a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx +++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx @@ -6,40 +6,22 @@ * Side Public License, v 1. */ -import React, { useMemo, useCallback } from 'react'; -import { get } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { css } from '@emotion/react'; +import React, { useMemo } from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiFlyoutResizable, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiFlyoutHeader, - EuiTitle, - EuiSpacer, - EuiPortal, - EuiPagination, - keys, - EuiButtonEmpty, - useEuiTheme, - useIsWithinMinBreakpoint, -} from '@elastic/eui'; import { Filter, Query, AggregateQuery, isOfAggregateQueryType } from '@kbn/es-query'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import type { DataTableColumnsMeta } from '@kbn/unified-data-table'; import type { DocViewsRegistry } from '@kbn/unified-doc-viewer'; -import { UnifiedDocViewer } from '@kbn/unified-doc-viewer-plugin/public'; -import useLocalStorage from 'react-use/lib/useLocalStorage'; +import { UnifiedDocViewerFlyout } from '@kbn/unified-doc-viewer-plugin/public'; import { useDiscoverServices } from '../../hooks/use_discover_services'; import { useFlyoutActions } from './use_flyout_actions'; import { useDiscoverCustomization } from '../../customizations'; import { DiscoverGridFlyoutActions } from './discover_grid_flyout_actions'; import { useProfileAccessor } from '../../context_awareness'; +export const FLYOUT_WIDTH_KEY = 'discover:flyoutWidth'; + export interface DiscoverGridFlyoutProps { savedSearchId?: string; filters?: Filter[]; @@ -56,13 +38,6 @@ export interface DiscoverGridFlyoutProps { setExpandedDoc: (doc?: DataTableRecord) => void; } -function getIndexByDocId(hits: DataTableRecord[], id: string) { - return hits.findIndex((h) => { - return h.id === id; - }); -} - -export const FLYOUT_WIDTH_KEY = 'discover:flyoutWidth'; /** * Flyout displaying an expanded Elasticsearch document */ @@ -83,100 +58,26 @@ export function DiscoverGridFlyout({ }: DiscoverGridFlyoutProps) { const services = useDiscoverServices(); const flyoutCustomization = useDiscoverCustomization('flyout'); - const { euiTheme } = useEuiTheme(); - const isXlScreen = useIsWithinMinBreakpoint('xl'); - const DEFAULT_WIDTH = euiTheme.base * 34; - const defaultWidth = flyoutCustomization?.size ?? DEFAULT_WIDTH; // Give enough room to search bar to not wrap - const [flyoutWidth, setFlyoutWidth] = useLocalStorage(FLYOUT_WIDTH_KEY, defaultWidth); - const minWidth = euiTheme.base * 24; - const maxWidth = euiTheme.breakpoint.xl; - const isEsqlQuery = isOfAggregateQueryType(query); + const isESQLQuery = isOfAggregateQueryType(query); // Get actual hit with updated highlighted searches const actualHit = useMemo(() => hits?.find(({ id }) => id === hit?.id) || hit, [hit, hits]); - const pageCount = useMemo(() => (hits ? hits.length : 0), [hits]); - const activePage = useMemo(() => { - const id = hit.id; - if (!hits || pageCount <= 1) { - return -1; - } - - return getIndexByDocId(hits, id); - }, [hits, hit, pageCount]); - - const setPage = useCallback( - (index: number) => { - if (hits && hits[index]) { - setExpandedDoc(hits[index]); - } - }, - [hits, setExpandedDoc] - ); - - const onKeyDown = useCallback( - (ev: React.KeyboardEvent) => { - const nodeName = get(ev, 'target.nodeName', null); - if (typeof nodeName === 'string' && nodeName.toLowerCase() === 'input') { - return; - } - if (ev.key === keys.ARROW_LEFT || ev.key === keys.ARROW_RIGHT) { - ev.preventDefault(); - ev.stopPropagation(); - setPage(activePage + (ev.key === keys.ARROW_RIGHT ? 1 : -1)); - } - }, - [activePage, setPage] - ); const { flyoutActions } = useFlyoutActions({ actions: flyoutCustomization?.actions, dataView, - rowIndex: hit.raw._index, - rowId: hit.raw._id, + rowIndex: actualHit.raw._index, + rowId: actualHit.raw._id, columns, filters, savedSearchId, }); - const addColumn = useCallback( - (columnName: string) => { - onAddColumn(columnName); - services.toastNotifications.addSuccess( - i18n.translate('discover.grid.flyout.toastColumnAdded', { - defaultMessage: `Column ''{columnName}'' was added`, - values: { columnName }, - }) - ); - }, - [onAddColumn, services.toastNotifications] - ); - - const removeColumn = useCallback( - (columnName: string) => { - onRemoveColumn(columnName); - services.toastNotifications.addSuccess( - i18n.translate('discover.grid.flyout.toastColumnRemoved', { - defaultMessage: `Column ''{columnName}'' was removed`, - values: { columnName }, - }) - ); - }, - [onRemoveColumn, services.toastNotifications] - ); - - const defaultFlyoutTitle = isEsqlQuery - ? i18n.translate('discover.grid.tableRow.docViewerEsqlDetailHeading', { - defaultMessage: 'Result', - }) - : i18n.translate('discover.grid.tableRow.docViewerDetailHeading', { - defaultMessage: 'Document', - }); - const getDocViewerAccessor = useProfileAccessor('getDocViewer', { record: actualHit, }); const docViewer = useMemo(() => { const getDocViewer = getDocViewerAccessor(() => ({ - title: flyoutCustomization?.title ?? defaultFlyoutTitle, + title: flyoutCustomization?.title, docViewsRegistry: (registry: DocViewsRegistry) => typeof flyoutCustomization?.docViewsRegistry === 'function' ? flyoutCustomization.docViewsRegistry(registry) @@ -184,125 +85,33 @@ export function DiscoverGridFlyout({ })); return getDocViewer({ record: actualHit }); - }, [defaultFlyoutTitle, flyoutCustomization, getDocViewerAccessor, actualHit]); - - const renderDefaultContent = useCallback( - () => ( - - ), - [ - actualHit, - addColumn, - columns, - columnsMeta, - dataView, - hits, - isEsqlQuery, - onFilter, - removeColumn, - docViewer.docViewsRegistry, - ] - ); - - const contentActions = useMemo( - () => ({ - filter: onFilter, - onAddColumn: addColumn, - onRemoveColumn: removeColumn, - }), - [onFilter, addColumn, removeColumn] - ); - - const bodyContent = flyoutCustomization?.Content ? ( - - ) : ( - renderDefaultContent() - ); + }, [flyoutCustomization, getDocViewerAccessor, actualHit]); return ( - - - - - - -

{docViewer.title}

-
-
- {activePage !== -1 && ( - - - - )} -
- {isEsqlQuery || !flyoutActions.length ? null : ( - <> - - - - )} -
- {bodyContent} - - - {i18n.translate('discover.grid.flyout.close', { - defaultMessage: 'Close', - })} - - -
-
+ 0 ? ( + + ) : null + } + flyoutWidthLocalStorageKey={FLYOUT_WIDTH_KEY} + FlyoutCustomBody={flyoutCustomization?.Content} + services={services} + docViewsRegistry={docViewer.docViewsRegistry} + isEsqlQuery={isESQLQuery} + hit={hit} + hits={hits} + dataView={dataView} + columns={columns} + columnsMeta={columnsMeta} + onAddColumn={onAddColumn} + onRemoveColumn={onRemoveColumn} + onClose={onClose} + onFilter={onFilter} + setExpandedDoc={setExpandedDoc} + /> ); } diff --git a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx index ad8b1c5a2f547b..523d254b853110 100644 --- a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx +++ b/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx @@ -113,16 +113,16 @@ describe('Doc table row component', () => { describe('details row', () => { it('should be empty by default', () => { const component = mountComponent(defaultProps); - expect(findTestSubject(component, 'docTableRowDetailsTitle').exists()).toBeFalsy(); + expect(findTestSubject(component, 'docViewerRowDetailsTitle').exists()).toBeFalsy(); }); it('should expand the detail row when the toggle arrow is clicked', () => { const component = mountComponent(defaultProps); const toggleButton = findTestSubject(component, 'docTableExpandToggleColumn'); - expect(findTestSubject(component, 'docTableRowDetailsTitle').exists()).toBeFalsy(); + expect(findTestSubject(component, 'docViewerRowDetailsTitle').exists()).toBeFalsy(); toggleButton.simulate('click'); - expect(findTestSubject(component, 'docTableRowDetailsTitle').exists()).toBeTruthy(); + expect(findTestSubject(component, 'docViewerRowDetailsTitle').exists()).toBeTruthy(); }); it('should hide the single/surrounding views for ES|QL mode', () => { @@ -133,7 +133,7 @@ describe('Doc table row component', () => { const component = mountComponent(props); const toggleButton = findTestSubject(component, 'docTableExpandToggleColumn'); toggleButton.simulate('click'); - expect(findTestSubject(component, 'docTableRowDetailsTitle').text()).toBe('Expanded result'); + expect(findTestSubject(component, 'docViewerRowDetailsTitle').text()).toBe('Expanded result'); expect(findTestSubject(component, 'docTableRowAction').length).toBeFalsy(); }); }); diff --git a/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx b/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx index 313b9e12090aa9..03cee5ad784624 100644 --- a/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx +++ b/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx @@ -58,7 +58,7 @@ export const TableRowDetails = ({ - +

{isEsqlMode && ( { const recordId = params.record.id; const prevValue = prev(params); return { - title: `${prevValue.title} #${recordId}`, + title: `${prevValue.title ?? 'Document'} #${recordId}`, docViewsRegistry: (registry) => { registry.add({ id: 'doc_view_mock', diff --git a/src/plugins/discover/public/context_awareness/types.ts b/src/plugins/discover/public/context_awareness/types.ts index 4bc75e6e1727d0..9dbec9fab8dae8 100644 --- a/src/plugins/discover/public/context_awareness/types.ts +++ b/src/plugins/discover/public/context_awareness/types.ts @@ -11,7 +11,7 @@ import type { DocViewsRegistry } from '@kbn/unified-doc-viewer'; import type { DataTableRecord } from '@kbn/discover-utils'; export interface DocViewerExtension { - title: string; + title: string | undefined; docViewsRegistry: (prevRegistry: DocViewsRegistry) => DocViewsRegistry; } diff --git a/src/plugins/discover/public/index.ts b/src/plugins/discover/public/index.ts index bd88c4d6dbe094..b54356c8fd50b2 100644 --- a/src/plugins/discover/public/index.ts +++ b/src/plugins/discover/public/index.ts @@ -24,7 +24,6 @@ export type { DiscoverCustomization, DiscoverCustomizationService, FlyoutCustomization, - FlyoutContentProps, SearchBarCustomization, UnifiedHistogramCustomization, TopNavCustomization, diff --git a/src/plugins/esql_datagrid/public/data_grid.tsx b/src/plugins/esql_datagrid/public/data_grid.tsx index c9e507295b9f3a..f45f1ce7f9ead6 100644 --- a/src/plugins/esql_datagrid/public/data_grid.tsx +++ b/src/plugins/esql_datagrid/public/data_grid.tsx @@ -62,7 +62,7 @@ const DataGrid: React.FC = (props) => { ) => ( { { const closeFlyoutSpy = jest.fn(); renderComponent(closeFlyoutSpy); await waitFor(() => { - userEvent.click(screen.getByTestId('esqlRowDetailsFlyoutCloseBtn')); + userEvent.click(screen.getByTestId('docViewerFlyoutCloseButton')); expect(closeFlyoutSpy).toHaveBeenCalled(); }); }); @@ -106,14 +106,14 @@ describe('RowViewer', () => { }, } as unknown as DataTableRecord); await waitFor(() => { - expect(screen.getByTestId('esqlTableRowNavigation')).toBeInTheDocument(); + expect(screen.getByTestId('docViewerFlyoutNavigation')).toBeInTheDocument(); }); }); it('doesnt display row navigation when there is only 1 row available', async () => { renderComponent(); await waitFor(() => { - expect(screen.queryByTestId('esqlTableRowNavigation')).not.toBeInTheDocument(); + expect(screen.queryByTestId('docViewerFlyoutNavigation')).not.toBeInTheDocument(); }); }); }); diff --git a/src/plugins/esql_datagrid/public/row_viewer.tsx b/src/plugins/esql_datagrid/public/row_viewer.tsx index 35c2b807fbbb3f..d02c48b7c85e4a 100644 --- a/src/plugins/esql_datagrid/public/row_viewer.tsx +++ b/src/plugins/esql_datagrid/public/row_viewer.tsx @@ -6,34 +6,15 @@ * Side Public License, v 1. */ -import React, { useMemo, useCallback } from 'react'; -import { get } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { css } from '@emotion/react'; +import React, { useMemo } from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiFlyoutResizable, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiFlyoutHeader, - EuiTitle, - EuiPortal, - EuiPagination, - keys, - EuiButtonEmpty, - useEuiTheme, - useIsWithinMinBreakpoint, -} from '@elastic/eui'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import type { DataTableColumnsMeta } from '@kbn/unified-data-table'; -import { UnifiedDocViewer } from '@kbn/unified-doc-viewer-plugin/public'; -import useLocalStorage from 'react-use/lib/useLocalStorage'; +import { UnifiedDocViewerFlyout } from '@kbn/unified-doc-viewer-plugin/public'; import { NotificationsStart } from '@kbn/core-notifications-browser'; export interface RowViewerProps { - toastNotifications?: NotificationsStart; + notifications?: NotificationsStart; columns: string[]; columnsMeta?: DataTableColumnsMeta; hit: DataTableRecord; @@ -46,12 +27,6 @@ export interface RowViewerProps { setExpandedDoc: (doc?: DataTableRecord) => void; } -function getIndexByDocId(hits: DataTableRecord[], id: string) { - return hits.findIndex((h) => { - return h.id === id; - }); -} - export const FLYOUT_WIDTH_KEY = 'esqlTable:flyoutWidth'; /** * Flyout displaying an expanded ES|QL row @@ -62,172 +37,32 @@ export function RowViewer({ dataView, columns, columnsMeta, - toastNotifications, + notifications, flyoutType = 'push', onClose, onRemoveColumn, onAddColumn, setExpandedDoc, }: RowViewerProps) { - const { euiTheme } = useEuiTheme(); - - const isXlScreen = useIsWithinMinBreakpoint('xl'); - const DEFAULT_WIDTH = euiTheme.base * 34; - const defaultWidth = DEFAULT_WIDTH; - const [flyoutWidth, setFlyoutWidth] = useLocalStorage(FLYOUT_WIDTH_KEY, defaultWidth); - const minWidth = euiTheme.base * 24; - const maxWidth = euiTheme.breakpoint.xl; - - const actualHit = useMemo(() => hits?.find(({ id }) => id === hit?.id) || hit, [hit, hits]); - const pageCount = useMemo(() => (hits ? hits.length : 0), [hits]); - const activePage = useMemo(() => { - const id = hit.id; - if (!hits || pageCount <= 1) { - return -1; - } - - return getIndexByDocId(hits, id); - }, [hits, hit, pageCount]); - - const setPage = useCallback( - (index: number) => { - if (hits && hits[index]) { - setExpandedDoc(hits[index]); - } - }, - [hits, setExpandedDoc] - ); - - const onKeyDown = useCallback( - (ev: React.KeyboardEvent) => { - const nodeName = get(ev, 'target.nodeName', null); - if (typeof nodeName === 'string' && nodeName.toLowerCase() === 'input') { - return; - } - if (ev.key === keys.ARROW_LEFT || ev.key === keys.ARROW_RIGHT) { - ev.preventDefault(); - ev.stopPropagation(); - setPage(activePage + (ev.key === keys.ARROW_RIGHT ? 1 : -1)); - } - }, - [activePage, setPage] - ); - - const addColumn = useCallback( - (columnName: string) => { - onAddColumn(columnName); - toastNotifications?.toasts?.addSuccess?.( - i18n.translate('esqlDataGrid.grid.flyout.toastColumnAdded', { - defaultMessage: `Column '{columnName}' was added`, - values: { columnName }, - }) - ); - }, - [onAddColumn, toastNotifications] - ); - - const removeColumn = useCallback( - (columnName: string) => { - onRemoveColumn(columnName); - toastNotifications?.toasts?.addSuccess?.( - i18n.translate('esqlDataGrid.grid.flyout.toastColumnRemoved', { - defaultMessage: `Column '{columnName}' was removed`, - values: { columnName }, - }) - ); - }, - [onRemoveColumn, toastNotifications] - ); - - const renderDefaultContent = useCallback( - () => ( - - ), - [actualHit, addColumn, columns, columnsMeta, dataView, hits, removeColumn] - ); - - const bodyContent = renderDefaultContent(); + const services = useMemo(() => ({ toastNotifications: notifications?.toasts }), [notifications]); return ( - - - - - - -

- {i18n.translate('esqlDataGrid.grid.tableRow.docViewerEsqlDetailHeading', { - defaultMessage: 'Result', - })} -

-
-
- {activePage !== -1 && ( - - - - )} -
-
- {bodyContent} - - - {i18n.translate('esqlDataGrid.grid.flyout.close', { - defaultMessage: 'Close', - })} - - -
-
+ ); } diff --git a/src/plugins/esql_datagrid/tsconfig.json b/src/plugins/esql_datagrid/tsconfig.json index 5db30eb35fd20d..1d8685bf559829 100644 --- a/src/plugins/esql_datagrid/tsconfig.json +++ b/src/plugins/esql_datagrid/tsconfig.json @@ -22,10 +22,9 @@ "@kbn/core", "@kbn/ui-actions-plugin", "@kbn/field-formats-plugin", - "@kbn/i18n", "@kbn/unified-doc-viewer-plugin", "@kbn/core-notifications-browser", - "@kbn/shared-ux-utility" + "@kbn/shared-ux-utility", ], "exclude": [ "target/**/*", diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/doc_viewer_flyout.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/doc_viewer_flyout.tsx new file mode 100644 index 00000000000000..640dbdeb4abfa8 --- /dev/null +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/doc_viewer_flyout.tsx @@ -0,0 +1,311 @@ +/* + * 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 React, { useMemo, useCallback, type ComponentType } from 'react'; +import { get } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { css } from '@emotion/react'; +import type { DataView } from '@kbn/data-views-plugin/public'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiFlyoutResizable, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiTitle, + EuiSpacer, + EuiPortal, + EuiPagination, + keys, + EuiButtonEmpty, + useEuiTheme, + useIsWithinMinBreakpoint, + EuiFlyoutProps, +} from '@elastic/eui'; +import type { DataTableRecord } from '@kbn/discover-utils/types'; +import type { DataTableColumnsMeta } from '@kbn/unified-data-table'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; +import type { ToastsStart } from '@kbn/core-notifications-browser'; +import type { DocViewFilterFn, DocViewRenderProps } from '@kbn/unified-doc-viewer/types'; +import { UnifiedDocViewer } from '../lazy_doc_viewer'; + +export interface UnifiedDocViewerFlyoutProps { + 'data-test-subj'?: string; + flyoutTitle?: string; + flyoutDefaultWidth?: EuiFlyoutProps['size']; + flyoutActions?: React.ReactNode; + flyoutType?: 'push' | 'overlay'; + flyoutWidthLocalStorageKey?: string; + FlyoutCustomBody?: ComponentType<{ + actions: Pick; + doc: DataTableRecord; + renderDefaultContent: () => React.ReactNode; + }>; + services: { + toastNotifications?: ToastsStart; + }; + docViewsRegistry?: DocViewRenderProps['docViewsRegistry']; + isEsqlQuery: boolean; + columns: string[]; + columnsMeta?: DataTableColumnsMeta; + hit: DataTableRecord; + hits?: DataTableRecord[]; + dataView: DataView; + onAddColumn: (column: string) => void; + onClose: () => void; + onFilter?: DocViewFilterFn; + onRemoveColumn: (column: string) => void; + setExpandedDoc: (doc?: DataTableRecord) => void; +} + +function getIndexByDocId(hits: DataTableRecord[], id: string) { + return hits.findIndex((h) => { + return h.id === id; + }); +} + +export const FLYOUT_WIDTH_KEY = 'unifiedDocViewer:flyoutWidth'; +/** + * Flyout displaying an expanded row details + */ +export function UnifiedDocViewerFlyout({ + 'data-test-subj': dataTestSubj, + flyoutTitle, + flyoutActions, + flyoutDefaultWidth, + flyoutType, + flyoutWidthLocalStorageKey, + FlyoutCustomBody, + services, + docViewsRegistry, + isEsqlQuery, + hit, + hits, + dataView, + columns, + columnsMeta, + onFilter, + onClose, + onRemoveColumn, + onAddColumn, + setExpandedDoc, +}: UnifiedDocViewerFlyoutProps) { + const { euiTheme } = useEuiTheme(); + const isXlScreen = useIsWithinMinBreakpoint('xl'); + const DEFAULT_WIDTH = euiTheme.base * 34; + const defaultWidth = flyoutDefaultWidth ?? DEFAULT_WIDTH; // Give enough room to search bar to not wrap + const [flyoutWidth, setFlyoutWidth] = useLocalStorage( + flyoutWidthLocalStorageKey ?? FLYOUT_WIDTH_KEY, + defaultWidth + ); + const minWidth = euiTheme.base * 24; + const maxWidth = euiTheme.breakpoint.xl; + // Get actual hit with updated highlighted searches + const actualHit = useMemo(() => hits?.find(({ id }) => id === hit?.id) || hit, [hit, hits]); + const pageCount = useMemo(() => (hits ? hits.length : 0), [hits]); + const activePage = useMemo(() => { + const id = hit.id; + if (!hits || pageCount <= 1) { + return -1; + } + + return getIndexByDocId(hits, id); + }, [hits, hit, pageCount]); + + const setPage = useCallback( + (index: number) => { + if (hits && hits[index]) { + setExpandedDoc(hits[index]); + } + }, + [hits, setExpandedDoc] + ); + + const onKeyDown = useCallback( + (ev: React.KeyboardEvent) => { + const nodeClasses = get(ev, 'target.className', ''); + if (typeof nodeClasses === 'string' && nodeClasses.includes('euiDataGrid')) { + // ignore events triggered from the data grid + return; + } + + const nodeName = get(ev, 'target.nodeName', null); + if (typeof nodeName === 'string' && nodeName.toLowerCase() === 'input') { + // ignore events triggered from the search input + return; + } + if (ev.key === keys.ARROW_LEFT || ev.key === keys.ARROW_RIGHT) { + ev.preventDefault(); + ev.stopPropagation(); + setPage(activePage + (ev.key === keys.ARROW_RIGHT ? 1 : -1)); + } + }, + [activePage, setPage] + ); + + const addColumn = useCallback( + (columnName: string) => { + onAddColumn(columnName); + services.toastNotifications?.addSuccess( + i18n.translate('unifiedDocViewer.flyout.toastColumnAdded', { + defaultMessage: `Column ''{columnName}'' was added`, + values: { columnName }, + }) + ); + }, + [onAddColumn, services.toastNotifications] + ); + + const removeColumn = useCallback( + (columnName: string) => { + onRemoveColumn(columnName); + services.toastNotifications?.addSuccess( + i18n.translate('unifiedDocViewer.flyout.toastColumnRemoved', { + defaultMessage: `Column ''{columnName}'' was removed`, + values: { columnName }, + }) + ); + }, + [onRemoveColumn, services.toastNotifications] + ); + + const renderDefaultContent = useCallback( + () => ( + + ), + [ + actualHit, + addColumn, + columns, + columnsMeta, + dataView, + hits, + isEsqlQuery, + onFilter, + removeColumn, + docViewsRegistry, + ] + ); + + const contentActions = useMemo( + () => ({ + filter: onFilter, + onAddColumn: addColumn, + onRemoveColumn: removeColumn, + }), + [onFilter, addColumn, removeColumn] + ); + + const bodyContent = FlyoutCustomBody ? ( + + ) : ( + renderDefaultContent() + ); + + const defaultFlyoutTitle = isEsqlQuery + ? i18n.translate('unifiedDocViewer.flyout.docViewerEsqlDetailHeading', { + defaultMessage: 'Result', + }) + : i18n.translate('unifiedDocViewer.flyout.docViewerDetailHeading', { + defaultMessage: 'Document', + }); + const currentFlyoutTitle = flyoutTitle ?? defaultFlyoutTitle; + + return ( + + + + + + +

{currentFlyoutTitle}

+
+
+ {activePage !== -1 && ( + + + + )} +
+ {isEsqlQuery || !flyoutActions ? null : ( + <> + + {flyoutActions} + + )} +
+ {bodyContent} + + + {i18n.translate('unifiedDocViewer.flyout.closeButtonLabel', { + defaultMessage: 'Close', + })} + + +
+
+ ); +} diff --git a/packages/kbn-field-utils/src/components/field_description_icon_button/index.ts b/src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/index.ts similarity index 65% rename from packages/kbn-field-utils/src/components/field_description_icon_button/index.ts rename to src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/index.ts index 36ebc6ef3e114e..81cb2f5cbb9280 100644 --- a/packages/kbn-field-utils/src/components/field_description_icon_button/index.ts +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_flyout/index.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -export { - FieldDescriptionIconButton, - type FieldDescriptionIconButtonProps, -} from './field_description_icon_button'; +import { UnifiedDocViewerFlyout } from './doc_viewer_flyout'; + +// Required for usage in React.lazy +// eslint-disable-next-line import/no-default-export +export default UnifiedDocViewerFlyout; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx index e28df4d89d5bc8..6c65b9ddf0bdb5 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx @@ -7,8 +7,7 @@ */ import { monaco } from '@kbn/monaco'; -import { getHeight } from './get_height'; -import { MARGIN_BOTTOM } from './source'; +import { getHeight, DEFAULT_MARGIN_BOTTOM } from './get_height'; describe('getHeight', () => { Object.defineProperty(window, 'innerHeight', { writable: true, configurable: true, value: 500 }); @@ -32,28 +31,31 @@ describe('getHeight', () => { test('when using document explorer, returning the available height in the flyout', () => { const monacoMock = getMonacoMock(500, 0); - const height = getHeight(monacoMock, true); - expect(height).toBe(500 - MARGIN_BOTTOM); + const height = getHeight(monacoMock, true, DEFAULT_MARGIN_BOTTOM); + expect(height).toBe(484); + + const heightCustom = getHeight(monacoMock, true, 80); + expect(heightCustom).toBe(420); }); test('when using document explorer, returning the available height in the flyout has a minimun guarenteed height', () => { const monacoMock = getMonacoMock(500); - const height = getHeight(monacoMock, true); + const height = getHeight(monacoMock, true, DEFAULT_MARGIN_BOTTOM); expect(height).toBe(400); }); test('when using classic table, its displayed inline without scrolling', () => { const monacoMock = getMonacoMock(100); - const height = getHeight(monacoMock, false); + const height = getHeight(monacoMock, false, DEFAULT_MARGIN_BOTTOM); expect(height).toBe(1020); }); test('when using classic table, limited height > 500 lines to allow scrolling', () => { const monacoMock = getMonacoMock(1000); - const height = getHeight(monacoMock, false); + const height = getHeight(monacoMock, false, DEFAULT_MARGIN_BOTTOM); expect(height).toBe(5020); }); }); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx index dbab289018a637..5abade066cb952 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx @@ -6,9 +6,29 @@ * Side Public License, v 1. */ import { monaco } from '@kbn/monaco'; -import { MARGIN_BOTTOM, MAX_LINES_CLASSIC_TABLE, MIN_HEIGHT } from './source'; +import { MAX_LINES_CLASSIC_TABLE, MIN_HEIGHT } from './source'; -export function getHeight(editor: monaco.editor.IStandaloneCodeEditor, useDocExplorer: boolean) { +// Displayed margin of the tab content to the window bottom +export const DEFAULT_MARGIN_BOTTOM = 16; + +export function getTabContentAvailableHeight( + elementRef: HTMLElement | undefined, + decreaseAvailableHeightBy: number +): number { + if (!elementRef) { + return 0; + } + + // assign a good height filling the available space of the document flyout + const position = elementRef.getBoundingClientRect(); + return window.innerHeight - position.top - decreaseAvailableHeightBy; +} + +export function getHeight( + editor: monaco.editor.IStandaloneCodeEditor, + useDocExplorer: boolean, + decreaseAvailableHeightBy: number +) { const editorElement = editor?.getDomNode(); if (!editorElement) { return 0; @@ -16,9 +36,7 @@ export function getHeight(editor: monaco.editor.IStandaloneCodeEditor, useDocExp let result; if (useDocExplorer) { - // assign a good height filling the available space of the document flyout - const position = editorElement.getBoundingClientRect(); - result = window.innerHeight - position.top - MARGIN_BOTTOM; + result = getTabContentAvailableHeight(editorElement, decreaseAvailableHeightBy); } else { // takes care of the classic table, display a maximum of 500 lines // why not display it all? Due to performance issues when the browser needs to render it all diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx index 430da5e15f1ad2..bd88ec151189a2 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx @@ -18,7 +18,7 @@ import { ElasticRequestState } from '@kbn/unified-doc-viewer'; import { isLegacyTableEnabled, SEARCH_FIELDS_FROM_SOURCE } from '@kbn/discover-utils'; import { getUnifiedDocViewerServices } from '../../plugin'; import { useEsDocSearch } from '../../hooks'; -import { getHeight } from './get_height'; +import { getHeight, DEFAULT_MARGIN_BOTTOM } from './get_height'; import { JSONCodeEditorCommonMemoized } from '../json_code_editor'; interface SourceViewerProps { @@ -28,6 +28,7 @@ interface SourceViewerProps { textBasedHits?: DataTableRecord[]; hasLineNumbers: boolean; width?: number; + decreaseAvailableHeightBy?: number; requestState?: ElasticRequestState; onRefresh: () => void; } @@ -35,8 +36,6 @@ interface SourceViewerProps { // Ihe number of lines displayed without scrolling used for classic table, which renders the component // inline limitation was necessary to enable virtualized scrolling, which improves performance export const MAX_LINES_CLASSIC_TABLE = 500; -// Displayed margin of the code editor to the window bottom when rendered in the document explorer flyout -export const MARGIN_BOTTOM = 80; // DocViewer flyout has a footer // Minimum height for the source content to guarantee minimum space when the flyout is scrollable. export const MIN_HEIGHT = 400; @@ -47,6 +46,7 @@ export const DocViewerSource = ({ width, hasLineNumbers, textBasedHits, + decreaseAvailableHeightBy, onRefresh, }: SourceViewerProps) => { const [editor, setEditor] = useState(); @@ -85,7 +85,11 @@ export const DocViewerSource = ({ return; } - const height = getHeight(editor, useDocExplorer); + const height = getHeight( + editor, + useDocExplorer, + decreaseAvailableHeightBy ?? DEFAULT_MARGIN_BOTTOM + ); if (height === 0) { return; } @@ -95,7 +99,7 @@ export const DocViewerSource = ({ } else { setEditorHeight(height); } - }, [editor, jsonValue, useDocExplorer, setEditorHeight]); + }, [editor, jsonValue, useDocExplorer, setEditorHeight, decreaseAvailableHeightBy]); const loadingState = (
diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/__snapshots__/table_cell_actions.test.tsx.snap b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/__snapshots__/table_cell_actions.test.tsx.snap new file mode 100644 index 00000000000000..bbc8ee91569ad7 --- /dev/null +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/__snapshots__/table_cell_actions.test.tsx.snap @@ -0,0 +1,351 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TableActions getFieldCellActions should render correctly for undefined functions 1`] = ` +Array [ + , + , +] +`; + +exports[`TableActions getFieldCellActions should render correctly for undefined functions 2`] = ` +Array [ + , +] +`; + +exports[`TableActions getFieldCellActions should render the panels correctly for defined onFilter function 1`] = ` +Array [ + , + , + , +] +`; + +exports[`TableActions getFieldValueCellActions should render correctly for undefined functions 1`] = `Array []`; + +exports[`TableActions getFieldValueCellActions should render the panels correctly for defined onFilter function 1`] = ` +Array [ + , + , +] +`; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx index deb5e5a52fb7a1..0bdab73fe6c7fe 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx @@ -37,19 +37,19 @@ export const DocViewerLegacyTable = ({ const tableColumns = useMemo(() => { return !hideActionsColumn ? [ACTIONS_COLUMN, ...MAIN_COLUMNS] : MAIN_COLUMNS; }, [hideActionsColumn]); - const onToggleColumn = useCallback( - (field: string) => { - if (!onRemoveColumn || !onAddColumn || !columns) { - return; - } + + const onToggleColumn = useMemo(() => { + if (!onRemoveColumn || !onAddColumn || !columns) { + return undefined; + } + return (field: string) => { if (columns.includes(field)) { onRemoveColumn(field); } else { onAddColumn(field); } - }, - [onRemoveColumn, onAddColumn, columns] - ); + }; + }, [onRemoveColumn, onAddColumn, columns]); const onSetRowProps = useCallback(({ field: { field } }: FieldRecordLegacy) => { return { diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx index 0b187c6d5b884f..40d22652322941 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx @@ -20,7 +20,7 @@ interface TableActionsProps { flattenedField: unknown; fieldMapping?: DataViewField; onFilter: DocViewFilterFn; - onToggleColumn: (field: string) => void; + onToggleColumn: ((field: string) => void) | undefined; ignoredValue: boolean; } @@ -47,11 +47,13 @@ export const TableActions = ({ onClick={() => onFilter(fieldMapping, flattenedField, '-')} /> )} - onToggleColumn(field)} - /> + {onToggleColumn && ( + onToggleColumn(field)} + /> + )} {onFilter && ( ; - field: { - pinned: boolean; - onTogglePinned: (field: string) => void; - } & FieldRecordLegacy['field']; - value: FieldRecordLegacy['value']; -} +import { + type TableRow, + getFieldCellActions, + getFieldValueCellActions, + getFilterExistsDisabledWarning, + getFilterInOutPairDisabledWarning, +} from './table_cell_actions'; +import { + DEFAULT_MARGIN_BOTTOM, + getTabContentAvailableHeight, +} from '../doc_viewer_source/get_height'; + +export type FieldRecord = TableRow; interface ItemsEntry { pinnedItems: FieldRecord[]; restItems: FieldRecord[]; } -const MOBILE_OPTIONS = { header: false }; -const PAGE_SIZE_OPTIONS = [25, 50, 100]; +const MIN_NAME_COLUMN_WIDTH = 150; +const MAX_NAME_COLUMN_WIDTH = 350; +const PAGE_SIZE_OPTIONS = [25, 50, 100, 250, 500]; const DEFAULT_PAGE_SIZE = 25; const PINNED_FIELDS_KEY = 'discover:pinnedFields'; const PAGE_SIZE = 'discover:pageSize'; const SEARCH_TEXT = 'discover:searchText'; +const GRID_COLUMN_FIELD_NAME = 'name'; +const GRID_COLUMN_FIELD_VALUE = 'value'; + +const GRID_PROPS: Pick = { + columnVisibility: { + visibleColumns: ['name', 'value'], + setVisibleColumns: () => null, + }, + rowHeightsOptions: { defaultHeight: 'auto' }, + gridStyle: { + border: 'horizontal', + stripes: true, + rowHover: 'highlight', + header: 'underline', + cellPadding: 'm', + fontSize: 's', + }, +}; + const getPinnedFields = (dataViewId: string, storage: Storage): string[] => { const pinnedFieldsEntry = storage.get(PINNED_FIELDS_KEY); if ( @@ -114,18 +135,12 @@ export const DocViewerTable = ({ columnsMeta, hit, dataView, - hideActionsColumn, filter, + decreaseAvailableHeightBy, onAddColumn, onRemoveColumn, }: DocViewRenderProps) => { - const { euiTheme } = useEuiTheme(); - const [ref, setRef] = useState(null); - const dimensions = useResizeObserver(ref); - const showActionsInsideTableCell = dimensions?.width - ? dimensions.width > euiTheme.breakpoint.m - : false; - + const [containerRef, setContainerRef] = useState(null); const { fieldFormats, storage, uiSettings } = getUnifiedDocViewerServices(); const showMultiFields = uiSettings.get(SHOW_MULTIFIELDS); const currentDataViewId = dataView.id!; @@ -147,19 +162,18 @@ export const DocViewerTable = ({ const mapping = useCallback((name: string) => dataView.fields.getByName(name), [dataView.fields]); - const onToggleColumn = useCallback( - (field: string) => { - if (!onRemoveColumn || !onAddColumn || !columns) { - return; - } + const onToggleColumn = useMemo(() => { + if (!onRemoveColumn || !onAddColumn || !columns) { + return undefined; + } + return (field: string) => { if (columns.includes(field)) { onRemoveColumn(field); } else { onAddColumn(field); } - }, - [onRemoveColumn, onAddColumn, columns] - ); + }; + }, [onRemoveColumn, onAddColumn, columns]); const onTogglePinned = useCallback( (field: string) => { @@ -173,6 +187,15 @@ export const DocViewerTable = ({ [currentDataViewId, pinnedFields, storage] ); + const onSearch = useCallback( + (event: React.ChangeEvent) => { + const newSearchText = event.currentTarget.value; + updateSearchText(newSearchText, storage); + setSearchText(newSearchText); + }, + [storage] + ); + const fieldToItem = useCallback( (field: string, isPinned: boolean) => { const fieldMapping = mapping(field); @@ -193,7 +216,6 @@ export const DocViewerTable = ({ action: { onToggleColumn, onFilter: filter, - isActive: !!columns?.includes(field), flattenedField: flattened[field], }, field: { @@ -223,7 +245,6 @@ export const DocViewerTable = ({ hit, onToggleColumn, filter, - columns, columnsMeta, flattened, onTogglePinned, @@ -231,15 +252,6 @@ export const DocViewerTable = ({ ] ); - const handleOnChange = useCallback( - (event: React.ChangeEvent) => { - const newSearchText = event.currentTarget.value; - updateSearchText(newSearchText, storage); - setSearchText(newSearchText); - }, - [storage] - ); - const { pinnedItems, restItems } = Object.keys(flattened) .sort((fieldA, fieldB) => { const mappingA = mapping(fieldA); @@ -278,11 +290,12 @@ export const DocViewerTable = ({ } ); - const { curPageIndex, pageSize, totalPages, startIndex, changePageIndex, changePageSize } = - usePager({ - initialPageSize: getPageSize(storage), - totalItems: restItems.length, - }); + const rows = useMemo(() => [...pinnedItems, ...restItems], [pinnedItems, restItems]); + + const { curPageIndex, pageSize, totalPages, changePageIndex, changePageSize } = usePager({ + initialPageSize: getPageSize(storage), + totalItems: rows.length, + }); const showPagination = totalPages !== 0; const onChangePageSize = useCallback( @@ -293,126 +306,160 @@ export const DocViewerTable = ({ [changePageSize, storage] ); - const headers = [ - !hideActionsColumn && ( - - - - { + return showPagination + ? { + onChangeItemsPerPage: onChangePageSize, + onChangePage: changePageIndex, + pageIndex: curPageIndex, + pageSize, + pageSizeOptions: PAGE_SIZE_OPTIONS, + } + : undefined; + }, [showPagination, curPageIndex, pageSize, onChangePageSize, changePageIndex]); + + const fieldCellActions = useMemo( + () => getFieldCellActions({ rows, filter, onToggleColumn }), + [rows, filter, onToggleColumn] + ); + const fieldValueCellActions = useMemo( + () => getFieldValueCellActions({ rows, filter }), + [rows, filter] + ); + + useWindowSize(); // trigger re-render on window resize to recalculate the grid container height + const { width: containerWidth } = useResizeObserver(containerRef); + + const gridColumns: EuiDataGridProps['columns'] = useMemo( + () => [ + { + id: GRID_COLUMN_FIELD_NAME, + displayAsText: i18n.translate('unifiedDocViewer.fieldChooser.discoverField.name', { + defaultMessage: 'Field', + }), + initialWidth: Math.min( + Math.max(Math.round(containerWidth * 0.3), MIN_NAME_COLUMN_WIDTH), + MAX_NAME_COLUMN_WIDTH + ), + actions: false, + visibleCellActions: 3, + cellActions: fieldCellActions, + }, + { + id: GRID_COLUMN_FIELD_VALUE, + displayAsText: i18n.translate('unifiedDocViewer.fieldChooser.discoverField.value', { + defaultMessage: 'Value', + }), + actions: false, + visibleCellActions: 2, + cellActions: fieldValueCellActions, + }, + ], + [fieldCellActions, fieldValueCellActions, containerWidth] + ); + + const renderCellValue: EuiDataGridProps['renderCellValue'] = useCallback( + ({ rowIndex, columnId, isDetails }) => { + const row = rows[rowIndex]; + + if (!row) { + return null; + } + + const { + action: { flattenedField }, + field: { field, fieldMapping, fieldType, scripted, pinned }, + value: { formattedValue, ignored }, + } = row; + + if (columnId === 'name') { + return ( +
+ - - - - ), - - - - - - - , - - - - + +
+ ) : null} +
+ ); + } + + if (columnId === 'value') { + return ( + - - - , - ]; - - const renderRows = useCallback( - (items: FieldRecord[]) => { - return items.map( - ({ - action: { flattenedField, onFilter }, - field: { field, fieldMapping, fieldType, scripted, pinned }, - value: { formattedValue, ignored }, - }: FieldRecord) => { - return ( - - {!hideActionsColumn && ( - - - - )} - - - - - - - - ); - } + ); + } + + return null; + }, + [rows, searchText] + ); + + const renderCellPopover = useCallback( + (props: EuiDataGridCellPopoverElementProps) => { + const { columnId, children, cellActions, rowIndex } = props; + const row = rows[rowIndex]; + + let warningMessage: string | undefined; + if (columnId === GRID_COLUMN_FIELD_VALUE) { + warningMessage = getFilterInOutPairDisabledWarning(row); + } else if (columnId === GRID_COLUMN_FIELD_NAME) { + warningMessage = getFilterExistsDisabledWarning(row); + } + + return ( + <> + {children} + {cellActions} + {Boolean(warningMessage) && ( +
+ + +
+ )} + ); }, - [hideActionsColumn, showActionsInsideTableCell, onToggleColumn, onTogglePinned, searchText] + [rows] ); - const rowElements = [ - ...renderRows(pinnedItems), - ...renderRows(restItems.slice(startIndex, pageSize + startIndex)), - ]; + const containerHeight = containerRef + ? getTabContentAvailableHeight(containerRef, decreaseAvailableHeightBy ?? DEFAULT_MARGIN_BOTTOM) + : 0; return ( - + @@ -421,14 +468,14 @@ export const DocViewerTable = ({ - {rowElements.length === 0 ? ( + {rows.length === 0 ? (

) : ( - - - {headers} - {rowElements} - - - )} - - - - - - {showPagination && ( - - - + <> + + + + + + + )} ); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.test.tsx index 076ca2d67be105..86b6cb6acf8333 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.test.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.test.tsx @@ -6,56 +6,82 @@ * Side Public License, v 1. */ import React from 'react'; -import { render, screen } from '@testing-library/react'; -import { TableActions } from './table_cell_actions'; +import { getFieldCellActions, getFieldValueCellActions, TableRow } from './table_cell_actions'; import { DataViewField } from '@kbn/data-views-plugin/common'; describe('TableActions', () => { - it('should render the panels correctly for undefined onFilter function', () => { - render( - - ); - expect(screen.queryByTestId('addFilterForValueButton-message')).not.toBeInTheDocument(); - expect(screen.queryByTestId('addFilterOutValueButton-message')).not.toBeInTheDocument(); - expect(screen.queryByTestId('addExistsFilterButton-message')).not.toBeInTheDocument(); - expect(screen.getByTestId('toggleColumnButton-message')).not.toBeDisabled(); - expect(screen.getByTestId('togglePinFilterButton-message')).not.toBeDisabled(); + const rows: TableRow[] = [ + { + action: { + onFilter: jest.fn(), + flattenedField: 'flattenedField', + onToggleColumn: jest.fn(), + }, + field: { + pinned: true, + onTogglePinned: jest.fn(), + field: 'message', + fieldMapping: new DataViewField({ + type: 'keyword', + name: 'message', + searchable: true, + aggregatable: true, + }), + fieldType: 'keyword', + displayName: 'message', + scripted: false, + }, + value: { + ignored: undefined, + formattedValue: 'test', + }, + }, + ]; + + const Component = () =>

Component
; + const EuiCellParams = { + Component, + rowIndex: 0, + colIndex: 0, + columnId: 'test', + isExpanded: false, + }; + + describe('getFieldCellActions', () => { + it('should render correctly for undefined functions', () => { + expect( + getFieldCellActions({ rows, filter: undefined, onToggleColumn: jest.fn() }).map((item) => + item(EuiCellParams) + ) + ).toMatchSnapshot(); + + expect( + getFieldCellActions({ rows, filter: undefined, onToggleColumn: undefined }).map((item) => + item(EuiCellParams) + ) + ).toMatchSnapshot(); + }); + + it('should render the panels correctly for defined onFilter function', () => { + expect( + getFieldCellActions({ rows, filter: jest.fn(), onToggleColumn: jest.fn() }).map((item) => + item(EuiCellParams) + ) + ).toMatchSnapshot(); + }); }); - it('should render the panels correctly for defined onFilter function', () => { - render( - - ); - expect(screen.getByTestId('addFilterForValueButton-message')).not.toBeDisabled(); - expect(screen.getByTestId('addFilterOutValueButton-message')).not.toBeDisabled(); - expect(screen.getByTestId('addExistsFilterButton-message')).not.toBeDisabled(); - expect(screen.getByTestId('toggleColumnButton-message')).not.toBeDisabled(); - expect(screen.getByTestId('togglePinFilterButton-message')).not.toBeDisabled(); + describe('getFieldValueCellActions', () => { + it('should render correctly for undefined functions', () => { + expect( + getFieldValueCellActions({ rows, filter: undefined }).map((item) => item(EuiCellParams)) + ).toMatchSnapshot(); + }); + + it('should render the panels correctly for defined onFilter function', () => { + expect( + getFieldValueCellActions({ rows, filter: jest.fn() }).map((item) => item(EuiCellParams)) + ).toMatchSnapshot(); + }); }); }); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.tsx index cfbfd1b1cde031..7814405e092018 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_actions.tsx @@ -6,125 +6,210 @@ * Side Public License, v 1. */ -import React, { useCallback, useState } from 'react'; -import { - EuiButtonIcon, - EuiContextMenu, - EuiPopover, - EuiFlexGroup, - EuiFlexItem, - EuiToolTip, -} from '@elastic/eui'; +import React from 'react'; +import { EuiDataGridColumnCellActionProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { DataViewField } from '@kbn/data-views-plugin/public'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import { DocViewFilterFn, FieldRecordLegacy } from '@kbn/unified-doc-viewer/types'; + +export interface TableRow { + action: Omit; + field: { + pinned: boolean; + onTogglePinned: (field: string) => void; + } & FieldRecordLegacy['field']; + value: FieldRecordLegacy['value']; +} interface TableActionsProps { - mode?: 'inline' | 'as_popover'; - field: string; - pinned: boolean; - flattenedField: unknown; - fieldMapping?: DataViewField; - onFilter?: DocViewFilterFn; - onToggleColumn: (field: string) => void; - ignoredValue: boolean; - onTogglePinned: (field: string) => void; + Component: EuiDataGridColumnCellActionProps['Component']; + row: TableRow | undefined; // as we pass `rows[rowIndex]` it's safer to assume that `row` prop can be undefined } -interface PanelItem { - name: string; - 'aria-label': string; - toolTipContent?: string; - disabled?: boolean; - 'data-test-subj': string; - icon: string; - onClick: () => void; +export function isFilterInOutPairDisabled(row: TableRow | undefined): boolean { + if (!row) { + return false; + } + const { + action: { onFilter }, + field: { fieldMapping }, + value: { ignored }, + } = row; + + return Boolean(onFilter && (!fieldMapping || !fieldMapping.filterable || ignored)); } -export const TableActions = ({ - mode = 'as_popover', - pinned, - field, - fieldMapping, - flattenedField, - onToggleColumn, - onFilter, - ignoredValue, - onTogglePinned, -}: TableActionsProps) => { - const [isOpen, setIsOpen] = useState(false); - const openActionsLabel = i18n.translate('unifiedDocViewer.docView.table.actions.open', { - defaultMessage: 'Open actions', - }); - const actionsLabel = i18n.translate('unifiedDocViewer.docView.table.actions.label', { - defaultMessage: 'Actions', - }); +export function getFilterInOutPairDisabledWarning(row: TableRow | undefined): string | undefined { + if (!row || !isFilterInOutPairDisabled(row)) { + return undefined; + } + const { + field: { fieldMapping }, + value: { ignored }, + } = row; + + if (ignored) { + return i18n.translate( + 'unifiedDocViewer.docViews.table.ignoredValuesCanNotBeSearchedWarningMessage', + { + defaultMessage: 'Ignored values cannot be searched', + } + ); + } + + return !fieldMapping + ? i18n.translate( + 'unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedWarningMessage', + { + defaultMessage: 'Unindexed fields cannot be searched', + } + ) + : undefined; +} + +export const FilterIn: React.FC = ({ Component, row }) => { + if (!row) { + return null; + } + + const { + action: { onFilter, flattenedField }, + field: { field, fieldMapping }, + } = row; // Filters pair - const filtersPairDisabled = !fieldMapping || !fieldMapping.filterable || ignoredValue; const filterAddLabel = i18n.translate( 'unifiedDocViewer.docViews.table.filterForValueButtonTooltip', { defaultMessage: 'Filter for value', } ); - const filterAddAriaLabel = i18n.translate( - 'unifiedDocViewer.docViews.table.filterForValueButtonAriaLabel', - { defaultMessage: 'Filter for value' } + + if (!onFilter) { + return null; + } + + return ( + onFilter(fieldMapping, flattenedField, '+')} + > + {filterAddLabel} + ); +}; + +export const FilterOut: React.FC = ({ Component, row }) => { + if (!row) { + return null; + } + + const { + action: { onFilter, flattenedField }, + field: { field, fieldMapping }, + } = row; + + // Filters pair const filterOutLabel = i18n.translate( 'unifiedDocViewer.docViews.table.filterOutValueButtonTooltip', { defaultMessage: 'Filter out value', } ); - const filterOutAriaLabel = i18n.translate( - 'unifiedDocViewer.docViews.table.filterOutValueButtonAriaLabel', - { defaultMessage: 'Filter out value' } + + if (!onFilter) { + return null; + } + + return ( + onFilter(fieldMapping, flattenedField, '-')} + > + {filterOutLabel} + ); - const filtersPairToolTip = - (filtersPairDisabled && - i18n.translate('unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedTooltip', { - defaultMessage: 'Unindexed fields or ignored values cannot be searched', - })) || - undefined; +}; + +export function isFilterExistsDisabled(row: TableRow | undefined): boolean { + if (!row) { + return false; + } + const { + action: { onFilter }, + field: { fieldMapping }, + } = row; + + return Boolean(onFilter && (!fieldMapping || !fieldMapping.filterable || fieldMapping.scripted)); +} + +export function getFilterExistsDisabledWarning(row: TableRow | undefined): string | undefined { + if (!row || !isFilterExistsDisabled(row)) { + return undefined; + } + const { + field: { fieldMapping }, + } = row; + + return fieldMapping?.scripted + ? i18n.translate( + 'unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsWarningMessage', + { + defaultMessage: 'Unable to filter for presence of scripted fields', + } + ) + : undefined; +} + +export const FilterExist: React.FC = ({ Component, row }) => { + if (!row) { + return null; + } + + const { + action: { onFilter }, + field: { field }, + } = row; // Filter exists const filterExistsLabel = i18n.translate( 'unifiedDocViewer.docViews.table.filterForFieldPresentButtonTooltip', { defaultMessage: 'Filter for field present' } ); - const filterExistsAriaLabel = i18n.translate( - 'unifiedDocViewer.docViews.table.filterForFieldPresentButtonAriaLabel', - { defaultMessage: 'Filter for field present' } - ); - const filtersExistsDisabled = !fieldMapping || !fieldMapping.filterable; - const filtersExistsToolTip = - (filtersExistsDisabled && - (fieldMapping && fieldMapping.scripted - ? i18n.translate( - 'unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsTooltip', - { - defaultMessage: 'Unable to filter for presence of scripted fields', - } - ) - : i18n.translate( - 'unifiedDocViewer.docViews.table.unableToFilterForPresenceOfMetaFieldsTooltip', - { - defaultMessage: 'Unable to filter for presence of meta fields', - } - ))) || - undefined; - - // Toggle columns - const toggleColumnsLabel = i18n.translate( - 'unifiedDocViewer.docViews.table.toggleColumnInTableButtonTooltip', - { defaultMessage: 'Toggle column in table' } - ); - const toggleColumnsAriaLabel = i18n.translate( - 'unifiedDocViewer.docViews.table.toggleColumnInTableButtonAriaLabel', - { defaultMessage: 'Toggle column in table' } + + if (!onFilter) { + return null; + } + + return ( + onFilter('_exists_', field, '+')} + > + {filterExistsLabel} + ); +}; + +export const PinToggle: React.FC = ({ Component, row }) => { + if (!row) { + return null; + } + + const { + field: { field, pinned, onTogglePinned }, + } = row; // Pinned const pinnedLabel = pinned @@ -134,128 +219,101 @@ export const TableActions = ({ : i18n.translate('unifiedDocViewer.docViews.table.pinFieldLabel', { defaultMessage: 'Pin field', }); - const pinnedAriaLabel = pinned - ? i18n.translate('unifiedDocViewer.docViews.table.unpinFieldAriaLabel', { - defaultMessage: 'Unpin field', - }) - : i18n.translate('unifiedDocViewer.docViews.table.pinFieldAriaLabel', { - defaultMessage: 'Pin field', - }); const pinnedIconType = pinned ? 'pinFilled' : 'pin'; - const toggleOpenPopover = useCallback(() => setIsOpen((current) => !current), []); - const closePopover = useCallback(() => setIsOpen(false), []); - const togglePinned = useCallback(() => onTogglePinned(field), [field, onTogglePinned]); - const onClickAction = useCallback( - (callback: () => void) => () => { - callback(); - closePopover(); - }, - [closePopover] + return ( + onTogglePinned(field)} + > + {pinnedLabel} + ); +}; - let panelItems: PanelItem[] = [ - { - name: toggleColumnsLabel, - 'aria-label': toggleColumnsAriaLabel, - 'data-test-subj': `toggleColumnButton-${field}`, - icon: 'listAdd', - onClick: onClickAction(onToggleColumn.bind({}, field)), - }, - { - name: pinnedLabel, - 'aria-label': pinnedAriaLabel, - icon: pinnedIconType, - 'data-test-subj': `togglePinFilterButton-${field}`, - onClick: onClickAction(togglePinned), - }, - ]; - - if (onFilter) { - panelItems = [ - { - name: filterAddLabel, - 'aria-label': filterAddAriaLabel, - toolTipContent: filtersPairToolTip, - icon: 'plusInCircle', - disabled: filtersPairDisabled, - 'data-test-subj': `addFilterForValueButton-${field}`, - onClick: onClickAction(onFilter.bind({}, fieldMapping, flattenedField, '+')), - }, - { - name: filterOutLabel, - 'aria-label': filterOutAriaLabel, - toolTipContent: filtersPairToolTip, - icon: 'minusInCircle', - disabled: filtersPairDisabled, - 'data-test-subj': `addFilterOutValueButton-${field}`, - onClick: onClickAction(onFilter.bind({}, fieldMapping, flattenedField, '-')), - }, - { - name: filterExistsLabel, - 'aria-label': filterExistsAriaLabel, - toolTipContent: filtersExistsToolTip, - icon: 'filter', - disabled: filtersExistsDisabled, - 'data-test-subj': `addExistsFilterButton-${field}`, - onClick: onClickAction(onFilter.bind({}, '_exists_', field, '+')), - }, - ...panelItems, - ]; +export const ToggleColumn: React.FC = ({ Component, row }) => { + if (!row) { + return null; } - const panels = [ - { - id: 0, - title: actionsLabel, - items: panelItems, - }, - ]; + const { + action: { onToggleColumn }, + field: { field }, + } = row; - if (mode === 'inline') { - return ( - - {panels[0].items.map((item) => ( - - - - - - ))} - - ); + if (!onToggleColumn) { + return null; } + // Toggle column + const toggleColumnLabel = i18n.translate( + 'unifiedDocViewer.docViews.table.toggleColumnTableButtonTooltip', + { + defaultMessage: 'Toggle column in table', + } + ); + return ( - - } - isOpen={isOpen} - closePopover={closePopover} - display="block" - panelPaddingSize="none" + onToggleColumn(field)} > - - + {toggleColumnLabel} + ); }; + +export function getFieldCellActions({ + rows, + filter, + onToggleColumn, +}: { + rows: TableRow[]; + filter?: DocViewFilterFn; + onToggleColumn: ((field: string) => void) | undefined; +}) { + return [ + ...(filter + ? [ + ({ Component, rowIndex }: EuiDataGridColumnCellActionProps) => { + return ; + }, + ] + : []), + ...(onToggleColumn + ? [ + ({ Component, rowIndex }: EuiDataGridColumnCellActionProps) => { + return ; + }, + ] + : []), + ({ Component, rowIndex }: EuiDataGridColumnCellActionProps) => { + return ; + }, + ]; +} + +export function getFieldValueCellActions({ + rows, + filter, +}: { + rows: TableRow[]; + filter?: DocViewFilterFn; +}) { + return filter + ? [ + ({ Component, rowIndex }: EuiDataGridColumnCellActionProps) => { + return ; + }, + ({ Component, rowIndex }: EuiDataGridColumnCellActionProps) => { + return ; + }, + ] + : []; +} diff --git a/src/plugins/unified_doc_viewer/public/components/index.ts b/src/plugins/unified_doc_viewer/public/components/index.ts index b5f3a8948d689d..c7a2cef523f76b 100644 --- a/src/plugins/unified_doc_viewer/public/components/index.ts +++ b/src/plugins/unified_doc_viewer/public/components/index.ts @@ -7,6 +7,7 @@ */ export * from './doc_viewer'; +export * from './doc_viewer_flyout'; export * from './doc_viewer_source'; export * from './doc_viewer_table'; export * from './json_code_editor'; diff --git a/src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer.tsx b/src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer.tsx new file mode 100644 index 00000000000000..06bbb3e71bde3d --- /dev/null +++ b/src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer.tsx @@ -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 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 React from 'react'; +import { withSuspense } from '@kbn/shared-ux-utility'; +import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/src/services/types'; +import { EuiDelayRender, EuiSkeletonText } from '@elastic/eui'; + +const LazyUnifiedDocViewer = React.lazy(() => import('./doc_viewer')); +export const UnifiedDocViewer = withSuspense( + LazyUnifiedDocViewer, + + + +); diff --git a/src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer_flyout.tsx b/src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer_flyout.tsx new file mode 100644 index 00000000000000..e81dfaec2f3191 --- /dev/null +++ b/src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer_flyout.tsx @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 React from 'react'; +import { withSuspense } from '@kbn/shared-ux-utility'; +import type { UnifiedDocViewerFlyoutProps } from './doc_viewer_flyout/doc_viewer_flyout'; + +const LazyUnifiedDocViewerFlyout = React.lazy(() => import('./doc_viewer_flyout')); +export const UnifiedDocViewerFlyout = withSuspense( + LazyUnifiedDocViewerFlyout, + <> +); diff --git a/src/plugins/unified_doc_viewer/public/index.tsx b/src/plugins/unified_doc_viewer/public/index.tsx index ffe5c3f16d78cf..b594d8f06c42fe 100644 --- a/src/plugins/unified_doc_viewer/public/index.tsx +++ b/src/plugins/unified_doc_viewer/public/index.tsx @@ -9,7 +9,6 @@ import React from 'react'; import { withSuspense } from '@kbn/shared-ux-utility'; import { EuiDelayRender, EuiSkeletonText } from '@elastic/eui'; -import { DocViewRenderProps } from '@kbn/unified-doc-viewer/src/services/types'; import type { JsonCodeEditorProps } from './components'; import { UnifiedDocViewerPublicPlugin } from './plugin'; @@ -26,14 +25,8 @@ export const JsonCodeEditor = withSuspense( ); -const LazyUnifiedDocViewer = React.lazy(() => import('./components/doc_viewer')); -export const UnifiedDocViewer = withSuspense( - LazyUnifiedDocViewer, - - - -); - export { useEsDocSearch } from './hooks'; +export { UnifiedDocViewer } from './components/lazy_doc_viewer'; +export { UnifiedDocViewerFlyout } from './components/lazy_doc_viewer_flyout'; export const plugin = () => new UnifiedDocViewerPublicPlugin(); diff --git a/src/plugins/unified_doc_viewer/public/plugin.tsx b/src/plugins/unified_doc_viewer/public/plugin.tsx index 524a02eec9ee96..13027a2541084f 100644 --- a/src/plugins/unified_doc_viewer/public/plugin.tsx +++ b/src/plugins/unified_doc_viewer/public/plugin.tsx @@ -99,7 +99,7 @@ export class UnifiedDocViewerPublicPlugin defaultMessage: 'JSON', }), order: 20, - component: ({ hit, dataView, textBasedHits }) => { + component: ({ hit, dataView, textBasedHits, decreaseAvailableHeightBy }) => { return ( {}} /> ); diff --git a/src/plugins/unified_doc_viewer/tsconfig.json b/src/plugins/unified_doc_viewer/tsconfig.json index 43cfe7945f188d..fbe2ac83c5f1ac 100644 --- a/src/plugins/unified_doc_viewer/tsconfig.json +++ b/src/plugins/unified_doc_viewer/tsconfig.json @@ -30,7 +30,9 @@ "@kbn/react-field", "@kbn/ui-theme", "@kbn/discover-shared-plugin", - "@kbn/fields-metadata-plugin" + "@kbn/fields-metadata-plugin", + "@kbn/unified-data-table", + "@kbn/core-notifications-browser" ], "exclude": [ "target/**/*", diff --git a/test/accessibility/apps/discover.ts b/test/accessibility/apps/discover.ts index 454b48b97ebca4..abdfe096efab21 100644 --- a/test/accessibility/apps/discover.ts +++ b/test/accessibility/apps/discover.ts @@ -134,15 +134,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('a11y test for actions on a field', async () => { await PageObjects.discover.clickDocViewerTab('doc_view_table'); - if (await testSubjects.exists('openFieldActionsButton-Cancelled')) { - await testSubjects.click('openFieldActionsButton-Cancelled'); // Open the actions - } else { - await testSubjects.existOrFail('fieldActionsGroup-Cancelled'); - } + await dataGrid.expandFieldNameCellInFlyout('Cancelled'); await a11y.testAppSnapshot(); - if (await testSubjects.exists('openFieldActionsButton-Cancelled')) { - await testSubjects.click('openFieldActionsButton-Cancelled'); // Close the actions - } + await browser.pressKeys(browser.keys.ESCAPE); }); it('a11y test for data-grid table with columns', async () => { diff --git a/test/functional/apps/context/_filters.ts b/test/functional/apps/context/_filters.ts index 9aff3f6c805fc2..71cb9eefe2dd24 100644 --- a/test/functional/apps/context/_filters.ts +++ b/test/functional/apps/context/_filters.ts @@ -22,7 +22,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); const kibanaServer = getService('kibanaServer'); - const PageObjects = getPageObjects(['common', 'context']); + const PageObjects = getPageObjects(['common', 'context', 'discover']); const testSubjects = getService('testSubjects'); describe('context filters', function contextSize() { @@ -41,6 +41,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('inclusive filter should be addable via expanded data grid rows', async function () { await retry.waitFor(`filter ${TEST_ANCHOR_FILTER_FIELD} in filterbar`, async () => { await dataGrid.clickRowToggle({ isAnchorRow: true, renderMoreRows: true }); + await PageObjects.discover.findFieldByNameInDocViewer(TEST_ANCHOR_FILTER_FIELD); await dataGrid.clickFieldActionInFlyout( TEST_ANCHOR_FILTER_FIELD, 'addFilterForValueButton' diff --git a/test/functional/apps/dashboard/group1/embeddable_data_grid.ts b/test/functional/apps/dashboard/group1/embeddable_data_grid.ts index 010644b1d20294..0b2199a976d0b3 100644 --- a/test/functional/apps/dashboard/group1/embeddable_data_grid.ts +++ b/test/functional/apps/dashboard/group1/embeddable_data_grid.ts @@ -49,7 +49,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async function () { await dataGrid.clickRowToggle({ isAnchorRow: false, rowIndex: 0 }); const detailsEl = await dataGrid.getDetailsRows(); - const defaultMessageEl = await detailsEl[0].findByTestSubject('docTableRowDetailsTitle'); + const defaultMessageEl = await detailsEl[0].findByTestSubject('docViewerRowDetailsTitle'); expect(defaultMessageEl).to.be.ok(); await dataGrid.closeFlyout(); }); diff --git a/test/functional/apps/dashboard/group1/url_field_formatter.ts b/test/functional/apps/dashboard/group1/url_field_formatter.ts index 12863bcc17fc44..b408e0aed14d6c 100644 --- a/test/functional/apps/dashboard/group1/url_field_formatter.ts +++ b/test/functional/apps/dashboard/group1/url_field_formatter.ts @@ -19,6 +19,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ]); const kibanaServer = getService('kibanaServer'); const testSubjects = getService('testSubjects'); + const find = getService('find'); const browser = getService('browser'); const fieldName = 'clientip'; const deployment = getService('deployment'); @@ -82,13 +83,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.waitForWithTimeout(`${fieldName} is visible`, 30000, async () => { return await testSubjects.isDisplayed(`tableDocViewRow-${fieldName}-value`); }); - const fieldLink = await testSubjects.find(`tableDocViewRow-${fieldName}-value`); + const fieldLink = await find.byCssSelector( + `[data-test-subj="tableDocViewRow-${fieldName}-value"] a` + ); const fieldValue = await fieldLink.getVisibleText(); await fieldLink.click(); await retry.try(async () => { await checkUrl(fieldValue); }); }); + afterEach(async function () { const windowHandlers = await browser.getAllWindowHandles(); if (windowHandlers.length > 1) { diff --git a/test/functional/apps/discover/classic/_doc_table.ts b/test/functional/apps/discover/classic/_doc_table.ts index 7ab640cf42ee1c..7539cce991af86 100644 --- a/test/functional/apps/discover/classic/_doc_table.ts +++ b/test/functional/apps/discover/classic/_doc_table.ts @@ -161,7 +161,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); const detailsEl = await docTable.getDetailsRows(); const defaultMessageEl = await detailsEl[0].findByTestSubject( - 'docTableRowDetailsTitle' + 'docViewerRowDetailsTitle' ); expect(defaultMessageEl).to.be.ok(); }); @@ -187,14 +187,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); const detailsEl = await docTable.getDetailsRows(); const defaultMessageEl = await detailsEl[0].findByTestSubject( - 'docTableRowDetailsTitle' + 'docViewerRowDetailsTitle' ); expect(defaultMessageEl).to.be.ok(); await queryBar.submitQuery(); const nrOfFetchesResubmit = await PageObjects.discover.getNrOfFetches(); expect(nrOfFetchesResubmit).to.be.above(nrOfFetches); const defaultMessageElResubmit = await detailsEl[0].findByTestSubject( - 'docTableRowDetailsTitle' + 'docViewerRowDetailsTitle' ); expect(defaultMessageElResubmit).to.be.ok(); diff --git a/test/functional/apps/discover/classic/_esql_grid.ts b/test/functional/apps/discover/classic/_esql_grid.ts index 7dfd331acec12d..d2bacbcd4947a8 100644 --- a/test/functional/apps/discover/classic/_esql_grid.ts +++ b/test/functional/apps/discover/classic/_esql_grid.ts @@ -65,7 +65,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); - await testSubjects.existOrFail('docTableDetailsFlyout'); + await testSubjects.existOrFail('docViewerFlyout'); await PageObjects.discover.saveSearch(savedSearchESQL); @@ -81,7 +81,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); - await testSubjects.existOrFail('docTableDetailsFlyout'); + await testSubjects.existOrFail('docViewerFlyout'); await dashboardPanelActions.removePanelByTitle(savedSearchESQL); diff --git a/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts b/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts index 81fd740ba21fa4..ac77fe3f707147 100644 --- a/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts +++ b/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts @@ -163,7 +163,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async function () { await dataGrid.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); const detailsEl = await dataGrid.getDetailsRows(); - const defaultMessageEl = await detailsEl[0].findByTestSubject('docTableRowDetailsTitle'); + const defaultMessageEl = await detailsEl[0].findByTestSubject('docViewerRowDetailsTitle'); expect(defaultMessageEl).to.be.ok(); await dataGrid.closeFlyout(); }); @@ -185,9 +185,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should allow paginating docs in the flyout by clicking in the doc table', async function () { await retry.try(async function () { await dataGrid.clickRowToggle({ rowIndex: rowToInspect - 1 }); - await testSubjects.exists(`dscDocNavigationPage0`); + await testSubjects.exists(`docViewerFlyoutNavigationPage0`); await dataGrid.clickRowToggle({ rowIndex: rowToInspect }); - await testSubjects.exists(`dscDocNavigationPage1`); + await testSubjects.exists(`docViewerFlyoutNavigationPage1`); await dataGrid.closeFlyout(); }); }); diff --git a/test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts b/test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts index d22e8b39bd4a55..fad92414cfb1c8 100644 --- a/test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts +++ b/test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts @@ -43,7 +43,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { let fieldTokens: string[] | undefined = []; await retry.try(async () => { await dataGrid.clickRowToggle({ rowIndex: 0 }); - fieldTokens = await findFirstFieldIcons('docTableDetailsFlyout'); + fieldTokens = await findFirstFieldIcons('docViewerFlyout'); }); return fieldTokens; } diff --git a/test/functional/apps/discover/group3/_doc_viewer.ts b/test/functional/apps/discover/group3/_doc_viewer.ts index 8fa3a94b969e38..140129c6a251f8 100644 --- a/test/functional/apps/discover/group3/_doc_viewer.ts +++ b/test/functional/apps/discover/group3/_doc_viewer.ts @@ -41,13 +41,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('search', function () { - const itemsPerPage = 25; - beforeEach(async () => { await dataGrid.clickRowToggle(); await PageObjects.discover.isShowingDocViewer(); await retry.waitFor('rendered items', async () => { - return (await find.allByCssSelector('.kbnDocViewer__fieldName')).length === itemsPerPage; + return (await find.allByCssSelector('.kbnDocViewer__fieldName')).length > 0; }); }); @@ -95,7 +93,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // expect no changes in the list await retry.waitFor('all items', async () => { - return (await find.allByCssSelector('.kbnDocViewer__fieldName')).length === itemsPerPage; + return (await find.allByCssSelector('.kbnDocViewer__fieldName')).length > 0; }); }); }); diff --git a/test/functional/apps/discover/group7/_runtime_fields_editor.ts b/test/functional/apps/discover/group7/_runtime_fields_editor.ts index de43dc8e74e927..3028096adc60c1 100644 --- a/test/functional/apps/discover/group7/_runtime_fields_editor.ts +++ b/test/functional/apps/discover/group7/_runtime_fields_editor.ts @@ -105,7 +105,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // check it in the doc viewer too await dataGrid.clickRowToggle({ rowIndex: 0 }); - await testSubjects.click('fieldDescriptionPopoverButton-agent'); + await dataGrid.expandFieldNameCellInFlyout('agent'); await retry.waitFor('doc viewer popover text', async () => { return (await testSubjects.getVisibleText('fieldDescription-agent')) === customDescription2; }); diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts index 18282442696ff5..cb225c45d1ea0b 100644 --- a/test/functional/services/data_grid.ts +++ b/test/functional/services/data_grid.ts @@ -268,7 +268,7 @@ export class DataGridService extends FtrService { } public async getDetailsRows(): Promise { - return await this.testSubjects.findAll('docTableDetailsFlyout'); + return await this.testSubjects.findAll('docViewerFlyout'); } public async closeFlyout() { @@ -452,17 +452,30 @@ export class DataGridService extends FtrService { return await tableDocViewRow.findByTestSubject(`~removeInclusiveFilterButton`); } + public async showFieldCellActionInFlyout(fieldName: string, actionName: string): Promise { + const cellSelector = ['addFilterForValueButton', 'addFilterOutValueButton'].includes(actionName) + ? `tableDocViewRow-${fieldName}-value` + : `tableDocViewRow-${fieldName}-name`; + await this.testSubjects.click(cellSelector); + await this.retry.waitFor('grid cell actions to appear', async () => { + return this.testSubjects.exists(`${actionName}-${fieldName}`); + }); + } + public async clickFieldActionInFlyout(fieldName: string, actionName: string): Promise { - const openPopoverButtonSelector = `openFieldActionsButton-${fieldName}`; - const inlineButtonsGroupSelector = `fieldActionsGroup-${fieldName}`; - if (await this.testSubjects.exists(openPopoverButtonSelector)) { - await this.testSubjects.click(openPopoverButtonSelector); - } else { - await this.testSubjects.existOrFail(inlineButtonsGroupSelector); - } + await this.showFieldCellActionInFlyout(fieldName, actionName); await this.testSubjects.click(`${actionName}-${fieldName}`); } + public async expandFieldNameCellInFlyout(fieldName: string): Promise { + const buttonSelector = 'euiDataGridCellExpandButton'; + await this.testSubjects.click(`tableDocViewRow-${fieldName}-name`); + await this.retry.waitFor('grid cell actions to appear', async () => { + return this.testSubjects.exists(buttonSelector); + }); + await this.testSubjects.click(buttonSelector); + } + public async hasNoResults() { return await this.find.existsByCssSelector('.euiDataGrid__noResults'); } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index d8143a8c98bf34..57e13f649a3653 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -2396,12 +2396,12 @@ "discover.fieldChooser.discoverField.removeFieldTooltip": "Supprimer le champ du tableau", "discover.globalSearch.esqlSearchTitle": "Créer des recherches ES|QL", "discover.goToDiscoverButtonText": "Aller à Discover", - "discover.grid.flyout.documentNavigation": "Navigation dans le document", - "discover.grid.flyout.toastColumnAdded": "La colonne \"{columnName}\" a été ajoutée.", - "discover.grid.flyout.toastColumnRemoved": "La colonne \"{columnName}\" a été supprimée.", + "unifiedDocViewer.flyout.documentNavigation": "Navigation dans le document", + "unifiedDocViewer.flyout.toastColumnAdded": "La colonne \"{columnName}\" a été ajoutée.", + "unifiedDocViewer.flyout.toastColumnRemoved": "La colonne \"{columnName}\" a été supprimée.", "discover.grid.tableRow.actionsLabel": "Actions", - "discover.grid.tableRow.docViewerDetailHeading": "Document", - "discover.grid.tableRow.docViewerEsqlDetailHeading": "Ligne", + "unifiedDocViewer.flyout.docViewerDetailHeading": "Document", + "unifiedDocViewer.flyout.docViewerEsqlDetailHeading": "Ligne", "discover.grid.tableRow.mobileFlyoutActionsButton": "Actions", "discover.grid.tableRow.moreFlyoutActionsButton": "Plus d'actions", "discover.grid.tableRow.esqlDetailHeading": "Ligne développée", @@ -44235,8 +44235,6 @@ "uiActions.errors.incompatibleAction": "Action non compatible", "uiActions.triggers.rowClickkDescription": "Un clic sur une ligne de tableau", "uiActions.triggers.rowClickTitle": "Clic sur ligne de tableau", - "unifiedDocViewer.docView.table.actions.label": "Actions", - "unifiedDocViewer.docView.table.actions.open": "Actions ouvertes", "unifiedDocViewer.docView.table.ignored.multiAboveTooltip": "Une ou plusieurs valeurs dans ce champ sont trop longues et ne peuvent pas être recherchées ni filtrées.", "unifiedDocViewer.docView.table.ignored.multiMalformedTooltip": "Ce champ comporte une ou plusieurs valeurs mal formées qui ne peuvent pas être recherchées ni filtrées.", "unifiedDocViewer.docView.table.ignored.multiUnknownTooltip": "Une ou plusieurs valeurs dans ce champ ont été ignorées par Elasticsearch et ne peuvent pas être recherchées ni filtrées.", @@ -44253,7 +44251,6 @@ "unifiedDocViewer.docViews.table.filterOutValueButtonTooltip": "Exclure la valeur", "unifiedDocViewer.docViews.table.ignored.multiValueLabel": "Contient des valeurs ignorées", "unifiedDocViewer.docViews.table.ignored.singleValueLabel": "Valeur ignorée", - "unifiedDocViewer.docViews.table.pinFieldAriaLabel": "Épingler le champ", "unifiedDocViewer.docViews.table.pinFieldLabel": "Épingler le champ", "unifiedDocViewer.docViews.table.tableTitle": "Tableau", "unifiedDocViewer.docViews.table.toggleColumnInTableButtonAriaLabel": "Afficher/Masquer la colonne dans le tableau", @@ -44261,7 +44258,6 @@ "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfMetaFieldsTooltip": "Impossible de filtrer sur les champs méta", "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsTooltip": "Impossible de filtrer sur les champs scriptés", "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedTooltip": "Les champs non indexés ou les valeurs ignorées ne peuvent pas être recherchés", - "unifiedDocViewer.docViews.table.unpinFieldAriaLabel": "Désépingler le champ", "unifiedDocViewer.docViews.table.unpinFieldLabel": "Désépingler le champ", "unifiedDocViewer.fieldChooser.discoverField.actions": "Actions", "unifiedDocViewer.fieldChooser.discoverField.multiField": "champ multiple", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f5b22bce86c92f..34bfbb83ecfe1d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2393,12 +2393,12 @@ "discover.fieldChooser.discoverField.removeFieldTooltip": "フィールドを表から削除", "discover.globalSearch.esqlSearchTitle": "ES|QLクエリを作成", "discover.goToDiscoverButtonText": "Discoverに移動", - "discover.grid.flyout.documentNavigation": "ドキュメントナビゲーション", - "discover.grid.flyout.toastColumnAdded": "列'{columnName}'が追加されました", - "discover.grid.flyout.toastColumnRemoved": "列'{columnName}'が削除されました", + "unifiedDocViewer.flyout.documentNavigation": "ドキュメントナビゲーション", + "unifiedDocViewer.flyout.toastColumnAdded": "列'{columnName}'が追加されました", + "unifiedDocViewer.flyout.toastColumnRemoved": "列'{columnName}'が削除されました", "discover.grid.tableRow.actionsLabel": "アクション", - "discover.grid.tableRow.docViewerDetailHeading": "ドキュメント", - "discover.grid.tableRow.docViewerEsqlDetailHeading": "行", + "unifiedDocViewer.flyout.docViewerDetailHeading": "ドキュメント", + "unifiedDocViewer.flyout.docViewerEsqlDetailHeading": "行", "discover.grid.tableRow.mobileFlyoutActionsButton": "アクション", "discover.grid.tableRow.moreFlyoutActionsButton": "さらにアクションを表示", "discover.grid.tableRow.esqlDetailHeading": "展開された行", @@ -44211,8 +44211,6 @@ "uiActions.errors.incompatibleAction": "操作に互換性がありません", "uiActions.triggers.rowClickkDescription": "テーブル行をクリック", "uiActions.triggers.rowClickTitle": "テーブル行クリック", - "unifiedDocViewer.docView.table.actions.label": "アクション", - "unifiedDocViewer.docView.table.actions.open": "アクションを開く", "unifiedDocViewer.docView.table.ignored.multiAboveTooltip": "このフィールドの1つ以上の値が長すぎるため、検索またはフィルタリングできません。", "unifiedDocViewer.docView.table.ignored.multiMalformedTooltip": "このフィールドは、検索またはフィルタリングできない正しくない形式の値が1つ以上あります。", "unifiedDocViewer.docView.table.ignored.multiUnknownTooltip": "このフィールドの1つ以上の値がElasticsearchによって無視されたため、検索またはフィルタリングできません。", @@ -44229,7 +44227,6 @@ "unifiedDocViewer.docViews.table.filterOutValueButtonTooltip": "値を除外", "unifiedDocViewer.docViews.table.ignored.multiValueLabel": "無視された値を含む", "unifiedDocViewer.docViews.table.ignored.singleValueLabel": "無視された値", - "unifiedDocViewer.docViews.table.pinFieldAriaLabel": "フィールドを固定", "unifiedDocViewer.docViews.table.pinFieldLabel": "フィールドを固定", "unifiedDocViewer.docViews.table.tableTitle": "表", "unifiedDocViewer.docViews.table.toggleColumnInTableButtonAriaLabel": "表の列を切り替える", @@ -44237,7 +44234,6 @@ "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfMetaFieldsTooltip": "メタフィールドの有無でフィルタリングできません", "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsTooltip": "スクリプトフィールドの有無でフィルタリングできません", "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedTooltip": "インデックスがないフィールドまたは無視された値は検索できません", - "unifiedDocViewer.docViews.table.unpinFieldAriaLabel": "フィールドを固定解除", "unifiedDocViewer.docViews.table.unpinFieldLabel": "フィールドを固定解除", "unifiedDocViewer.fieldChooser.discoverField.actions": "アクション", "unifiedDocViewer.fieldChooser.discoverField.multiField": "複数フィールド", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d94eb2aed9eb78..2b6307f7417bb5 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2397,12 +2397,12 @@ "discover.fieldChooser.discoverField.removeFieldTooltip": "从表中移除字段", "discover.globalSearch.esqlSearchTitle": "创建 ES|QL 查询", "discover.goToDiscoverButtonText": "前往 Discover", - "discover.grid.flyout.documentNavigation": "文档导航", - "discover.grid.flyout.toastColumnAdded": "已添加列“{columnName}”", - "discover.grid.flyout.toastColumnRemoved": "已移除列“{columnName}”", + "unifiedDocViewer.flyout.documentNavigation": "文档导航", + "unifiedDocViewer.flyout.toastColumnAdded": "已添加列“{columnName}”", + "unifiedDocViewer.flyout.toastColumnRemoved": "已移除列“{columnName}”", "discover.grid.tableRow.actionsLabel": "操作", - "discover.grid.tableRow.docViewerDetailHeading": "文档", - "discover.grid.tableRow.docViewerEsqlDetailHeading": "行", + "unifiedDocViewer.flyout.docViewerDetailHeading": "文档", + "unifiedDocViewer.flyout.docViewerEsqlDetailHeading": "行", "discover.grid.tableRow.mobileFlyoutActionsButton": "操作", "discover.grid.tableRow.moreFlyoutActionsButton": "更多操作", "discover.grid.tableRow.esqlDetailHeading": "已展开行", @@ -44259,8 +44259,6 @@ "uiActions.errors.incompatibleAction": "操作不兼容", "uiActions.triggers.rowClickkDescription": "表格行的单击", "uiActions.triggers.rowClickTitle": "表格行单击", - "unifiedDocViewer.docView.table.actions.label": "操作", - "unifiedDocViewer.docView.table.actions.open": "打开操作", "unifiedDocViewer.docView.table.ignored.multiAboveTooltip": "此字段中的一个或多个值过长,无法搜索或筛选。", "unifiedDocViewer.docView.table.ignored.multiMalformedTooltip": "此字段包含一个或多个格式错误的值,无法搜索或筛选。", "unifiedDocViewer.docView.table.ignored.multiUnknownTooltip": "此字段中的一个或多个值被 Elasticsearch 忽略,无法搜索或筛选。", @@ -44277,7 +44275,6 @@ "unifiedDocViewer.docViews.table.filterOutValueButtonTooltip": "筛除值", "unifiedDocViewer.docViews.table.ignored.multiValueLabel": "包含被忽略的值", "unifiedDocViewer.docViews.table.ignored.singleValueLabel": "被忽略的值", - "unifiedDocViewer.docViews.table.pinFieldAriaLabel": "固定字段", "unifiedDocViewer.docViews.table.pinFieldLabel": "固定字段", "unifiedDocViewer.docViews.table.tableTitle": "表", "unifiedDocViewer.docViews.table.toggleColumnInTableButtonAriaLabel": "在表中切换列", @@ -44285,7 +44282,6 @@ "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfMetaFieldsTooltip": "无法筛选元数据字段是否存在", "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsTooltip": "无法筛选脚本字段是否存在", "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedTooltip": "无法搜索未编入索引的字段或被忽略的值", - "unifiedDocViewer.docViews.table.unpinFieldAriaLabel": "取消固定字段", "unifiedDocViewer.docViews.table.unpinFieldLabel": "取消固定字段", "unifiedDocViewer.fieldChooser.discoverField.actions": "操作", "unifiedDocViewer.fieldChooser.discoverField.multiField": "多字段", diff --git a/x-pack/test_serverless/functional/test_suites/common/context/_filters.ts b/x-pack/test_serverless/functional/test_suites/common/context/_filters.ts index 47f864787e6c57..95197c1e20bd67 100644 --- a/x-pack/test_serverless/functional/test_suites/common/context/_filters.ts +++ b/x-pack/test_serverless/functional/test_suites/common/context/_filters.ts @@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); const kibanaServer = getService('kibanaServer'); - const PageObjects = getPageObjects(['common', 'context', 'svlCommonPage']); + const PageObjects = getPageObjects(['common', 'context', 'svlCommonPage', 'discover']); const testSubjects = getService('testSubjects'); describe('context filters', function contextSize() { @@ -42,6 +42,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('inclusive filter should be addable via expanded data grid rows', async function () { await retry.waitFor(`filter ${TEST_ANCHOR_FILTER_FIELD} in filterbar`, async () => { await dataGrid.clickRowToggle({ isAnchorRow: true, renderMoreRows: true }); + await PageObjects.discover.findFieldByNameInDocViewer(TEST_ANCHOR_FILTER_FIELD); await dataGrid.clickFieldActionInFlyout( TEST_ANCHOR_FILTER_FIELD, 'addFilterForValueButton' diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts index 2ca4c5f8569377..5b66781ff2ba7d 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts @@ -164,7 +164,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async function () { await dataGrid.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); const detailsEl = await dataGrid.getDetailsRows(); - const defaultMessageEl = await detailsEl[0].findByTestSubject('docTableRowDetailsTitle'); + const defaultMessageEl = await detailsEl[0].findByTestSubject('docViewerRowDetailsTitle'); expect(defaultMessageEl).to.be.ok(); await dataGrid.closeFlyout(); }); @@ -186,9 +186,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should allow paginating docs in the flyout by clicking in the doc table', async function () { await retry.try(async function () { await dataGrid.clickRowToggle({ rowIndex: rowToInspect - 1 }); - await testSubjects.exists(`dscDocNavigationPage0`); + await testSubjects.exists(`docViewerFlyoutNavigationPage0`); await dataGrid.clickRowToggle({ rowIndex: rowToInspect }); - await testSubjects.exists(`dscDocNavigationPage1`); + await testSubjects.exists(`docViewerFlyoutNavigationPage1`); await dataGrid.closeFlyout(); }); }); From 6d39b8a432a427497631f6bf6be23d0d9bb94126 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Wed, 19 Jun 2024 10:05:27 -0400 Subject: [PATCH 094/123] [Embeddables Rebuild] Fix runtime state types. (#186194) Fixes runtime state types, requiring them to be specified twice. --- .../get_control_group_factory.tsx | 6 +- .../react_controls/control_group/types.ts | 2 +- .../public/app/render_examples.tsx | 2 +- .../data_table_react_embeddable.tsx | 4 +- .../react_embeddables/data_table/types.ts | 2 + .../eui_markdown_react_embeddable.tsx | 7 +- .../react_embeddables/eui_markdown/types.ts | 2 + .../field_list_react_embeddable.tsx | 8 +- .../react_embeddables/field_list/types.ts | 9 +- .../saved_book_react_embeddable.tsx | 4 +- .../react_embeddables/saved_book/types.ts | 2 +- .../search/search_react_embeddable.tsx | 4 +- .../public/react_embeddables/search/types.ts | 2 + .../public/filter_debugger_embeddable.tsx | 2 +- .../react_embeddable_registry.ts | 20 +- .../react_embeddable_renderer.tsx | 21 +- .../react_embeddable_state.ts | 9 +- .../public/react_embeddable_system/types.ts | 25 +- .../get_image_embeddable_factory.tsx | 1 + .../embeddable_change_point_chart_factory.tsx | 4 +- .../plugins/maps/public/lens/passive_map.tsx | 4 +- .../react_embeddable/map_react_embeddable.tsx | 8 +- .../public/react_embeddable/map_renderer.tsx | 4 +- .../maps/public/react_embeddable/types.ts | 2 + .../anomaly_charts_embeddable_factory.tsx | 285 +++++++++--------- ...omaly_swimlane_embeddable_factory.test.tsx | 6 +- .../anomaly_swimlane_embeddable_factory.tsx | 4 +- ...ingle_metric_viewer_embeddable_factory.tsx | 4 +- .../shared_components/anomaly_swim_lane.tsx | 6 +- .../react_embeddable_factory.tsx | 1 + .../react_embeddable_factory.tsx | 1 + .../react_embeddable_factory.tsx | 1 + .../log_stream_react_embeddable.tsx | 6 +- .../alerts/slo_alerts_embeddable_factory.tsx | 6 +- .../error_budget_react_embeddable_factory.tsx | 6 +- .../slo/overview/slo_embeddable_factory.tsx | 6 +- 36 files changed, 287 insertions(+), 199 deletions(-) diff --git a/examples/controls_example/public/react_controls/control_group/get_control_group_factory.tsx b/examples/controls_example/public/react_controls/control_group/get_control_group_factory.tsx index 703d31f18db1d6..d78feb6743795d 100644 --- a/examples/controls_example/public/react_controls/control_group/get_control_group_factory.tsx +++ b/examples/controls_example/public/react_controls/control_group/get_control_group_factory.tsx @@ -52,8 +52,8 @@ export const getControlGroupEmbeddableFactory = (services: { }) => { const controlGroupEmbeddableFactory: ReactEmbeddableFactory< ControlGroupSerializedState, - ControlGroupApi, - ControlGroupRuntimeState + ControlGroupRuntimeState, + ControlGroupApi > = { type: CONTROL_GROUP_TYPE, deserializeState: (state) => deserializeControlGroup(state), @@ -117,7 +117,7 @@ export const getControlGroupEmbeddableFactory = (services: { }, snapshotRuntimeState: () => { // TODO: Remove this if it ends up being unnecessary - return {} as unknown as ControlGroupSerializedState; + return {} as unknown as ControlGroupRuntimeState; }, dataLoading: dataLoading$, children$: children$ as PublishingSubject<{ diff --git a/examples/controls_example/public/react_controls/control_group/types.ts b/examples/controls_example/public/react_controls/control_group/types.ts index b1807d31d801b3..9fb6af3cef803b 100644 --- a/examples/controls_example/public/react_controls/control_group/types.ts +++ b/examples/controls_example/public/react_controls/control_group/types.ts @@ -42,7 +42,7 @@ export type ControlGroupUnsavedChanges = Omit< export type ControlPanelState = DefaultControlState & { type: string; order: number }; export type ControlGroupApi = PresentationContainer & - DefaultEmbeddableApi & + DefaultEmbeddableApi & PublishesFilters & PublishesDataViews & HasSerializedChildState & diff --git a/examples/embeddable_examples/public/app/render_examples.tsx b/examples/embeddable_examples/public/app/render_examples.tsx index 4998b3bc5a59c9..7e268e29f620e1 100644 --- a/examples/embeddable_examples/public/app/render_examples.tsx +++ b/examples/embeddable_examples/public/app/render_examples.tsx @@ -98,7 +98,7 @@ export const RenderExamples = () => { - + key={hidePanelChrome ? 'hideChrome' : 'showChrome'} type={SEARCH_EMBEDDABLE_ID} getParentApi={() => parentApi} diff --git a/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx index 3bf161bd51490a..d373a008963466 100644 --- a/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx @@ -26,12 +26,12 @@ import { BehaviorSubject } from 'rxjs'; import { StartDeps } from '../../plugin'; import { DATA_TABLE_ID } from './constants'; import { initializeDataTableQueries } from './data_table_queries'; -import { DataTableApi, DataTableSerializedState } from './types'; +import { DataTableApi, DataTableRuntimeState, DataTableSerializedState } from './types'; export const getDataTableFactory = ( core: CoreStart, services: StartDeps -): ReactEmbeddableFactory => ({ +): ReactEmbeddableFactory => ({ type: DATA_TABLE_ID, deserializeState: (state) => { return state.rawState as DataTableSerializedState; diff --git a/examples/embeddable_examples/public/react_embeddables/data_table/types.ts b/examples/embeddable_examples/public/react_embeddables/data_table/types.ts index d693577bc89fb5..787bda380bcfa3 100644 --- a/examples/embeddable_examples/public/react_embeddables/data_table/types.ts +++ b/examples/embeddable_examples/public/react_embeddables/data_table/types.ts @@ -15,4 +15,6 @@ import { export type DataTableSerializedState = SerializedTitles & SerializedTimeRange; +export type DataTableRuntimeState = DataTableSerializedState; + export type DataTableApi = DefaultEmbeddableApi & PublishesDataLoading; diff --git a/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx index 64cdf1cb06e08d..cd36c6dc5f1c9a 100644 --- a/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx @@ -19,10 +19,15 @@ import { euiThemeVars } from '@kbn/ui-theme'; import React from 'react'; import { BehaviorSubject } from 'rxjs'; import { EUI_MARKDOWN_ID } from './constants'; -import { MarkdownEditorSerializedState, MarkdownEditorApi } from './types'; +import { + MarkdownEditorApi, + MarkdownEditorRuntimeState, + MarkdownEditorSerializedState, +} from './types'; export const markdownEmbeddableFactory: ReactEmbeddableFactory< MarkdownEditorSerializedState, + MarkdownEditorRuntimeState, MarkdownEditorApi > = { type: EUI_MARKDOWN_ID, diff --git a/examples/embeddable_examples/public/react_embeddables/eui_markdown/types.ts b/examples/embeddable_examples/public/react_embeddables/eui_markdown/types.ts index 31678aa4a2a33a..b341ffab1640c9 100644 --- a/examples/embeddable_examples/public/react_embeddables/eui_markdown/types.ts +++ b/examples/embeddable_examples/public/react_embeddables/eui_markdown/types.ts @@ -13,4 +13,6 @@ export type MarkdownEditorSerializedState = SerializedTitles & { content: string; }; +export type MarkdownEditorRuntimeState = MarkdownEditorSerializedState; + export type MarkdownEditorApi = DefaultEmbeddableApi; diff --git a/examples/embeddable_examples/public/react_embeddables/field_list/field_list_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/field_list/field_list_react_embeddable.tsx index 2931760310c2b4..6c296b00786e98 100644 --- a/examples/embeddable_examples/public/react_embeddables/field_list/field_list_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/field_list/field_list_react_embeddable.tsx @@ -25,7 +25,12 @@ import { cloneDeep } from 'lodash'; import React, { useEffect } from 'react'; import { BehaviorSubject, skip, Subscription, switchMap } from 'rxjs'; import { FIELD_LIST_DATA_VIEW_REF_NAME, FIELD_LIST_ID } from './constants'; -import { FieldListApi, Services, FieldListSerializedStateState } from './types'; +import { + FieldListApi, + Services, + FieldListSerializedStateState, + FieldListRuntimeState, +} from './types'; const DataViewPicker = withSuspense(LazyDataViewPicker, null); @@ -46,6 +51,7 @@ export const getFieldListFactory = ( ) => { const fieldListEmbeddableFactory: ReactEmbeddableFactory< FieldListSerializedStateState, + FieldListRuntimeState, FieldListApi > = { type: FIELD_LIST_ID, diff --git a/examples/embeddable_examples/public/react_embeddables/field_list/types.ts b/examples/embeddable_examples/public/react_embeddables/field_list/types.ts index 0da67bcd0f70b2..781f43754228c6 100644 --- a/examples/embeddable_examples/public/react_embeddables/field_list/types.ts +++ b/examples/embeddable_examples/public/react_embeddables/field_list/types.ts @@ -19,7 +19,14 @@ export type FieldListSerializedStateState = SerializedTitles & { selectedFieldNames?: string[]; }; -export type FieldListApi = DefaultEmbeddableApi & PublishesSelectedFields & PublishesDataViews; +export type FieldListRuntimeState = FieldListSerializedStateState; + +export type FieldListApi = DefaultEmbeddableApi< + FieldListSerializedStateState, + FieldListSerializedStateState +> & + PublishesSelectedFields & + PublishesDataViews; export interface Services { dataViews: DataViewsPublicPluginStart; diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx index 94e54b6ee350cc..0a9c3c4d7117b9 100644 --- a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx @@ -41,8 +41,8 @@ const bookSerializedStateIsByReference = ( export const getSavedBookEmbeddableFactory = (core: CoreStart) => { const savedBookEmbeddableFactory: ReactEmbeddableFactory< BookSerializedState, - BookApi, - BookRuntimeState + BookRuntimeState, + BookApi > = { type: SAVED_BOOK_ID, deserializeState: async (serializedState) => { diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts b/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts index ec855bbd38f964..362d95604cf973 100644 --- a/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts @@ -45,6 +45,6 @@ export interface BookRuntimeState Partial, SerializedTitles {} -export type BookApi = DefaultEmbeddableApi & +export type BookApi = DefaultEmbeddableApi & HasEditCapabilities & HasInPlaceLibraryTransforms; diff --git a/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx index 2b789a17da4ae5..ef73c179b8f8ee 100644 --- a/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx @@ -21,10 +21,10 @@ import React, { useEffect } from 'react'; import { BehaviorSubject, switchMap, tap } from 'rxjs'; import { SEARCH_EMBEDDABLE_ID } from './constants'; import { getCount } from './get_count'; -import { SearchApi, Services, SearchSerializedState } from './types'; +import { SearchApi, Services, SearchSerializedState, SearchRuntimeState } from './types'; export const getSearchEmbeddableFactory = (services: Services) => { - const factory: ReactEmbeddableFactory = { + const factory: ReactEmbeddableFactory = { type: SEARCH_EMBEDDABLE_ID, deserializeState: (state) => state.rawState, buildEmbeddable: async (state, buildApi, uuid, parentApi) => { diff --git a/examples/embeddable_examples/public/react_embeddables/search/types.ts b/examples/embeddable_examples/public/react_embeddables/search/types.ts index 835b2380d46a7e..c82213931a0029 100644 --- a/examples/embeddable_examples/public/react_embeddables/search/types.ts +++ b/examples/embeddable_examples/public/react_embeddables/search/types.ts @@ -20,6 +20,8 @@ import { export type SearchSerializedState = SerializedTimeRange; +export type SearchRuntimeState = SearchSerializedState; + export type SearchApi = DefaultEmbeddableApi & PublishesDataViews & PublishesDataLoading & diff --git a/examples/portable_dashboards_example/public/filter_debugger_embeddable.tsx b/examples/portable_dashboards_example/public/filter_debugger_embeddable.tsx index fd2c23731011bf..8c5d136640b1da 100644 --- a/examples/portable_dashboards_example/public/filter_debugger_embeddable.tsx +++ b/examples/portable_dashboards_example/public/filter_debugger_embeddable.tsx @@ -18,7 +18,7 @@ import { FILTER_DEBUGGER_EMBEDDABLE_ID } from './constants'; export type Api = DefaultEmbeddableApi<{}>; -export const factory: ReactEmbeddableFactory<{}, Api> = { +export const factory: ReactEmbeddableFactory<{}, {}, Api> = { type: FILTER_DEBUGGER_EMBEDDABLE_ID, deserializeState: () => { return {}; diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts index b1d67cc8a1d905..eea89f191db82a 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { DefaultEmbeddableApi, ReactEmbeddableFactory } from './types'; -const registry: { [key: string]: () => Promise> } = {}; +const registry: { [key: string]: () => Promise> } = {}; /** * Registers a new React embeddable factory. This should be called at plugin start time. @@ -20,11 +20,14 @@ const registry: { [key: string]: () => Promise> */ export const registerReactEmbeddableFactory = < SerializedState extends object = object, - Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, - RuntimeState extends object = SerializedState + RuntimeState extends object = SerializedState, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi< + SerializedState, + RuntimeState + > >( type: string, - getFactory: () => Promise> + getFactory: () => Promise> ) => { if (registry[type] !== undefined) throw new Error( @@ -40,11 +43,14 @@ export const reactEmbeddableRegistryHasKey = (key: string) => registry[key] !== export const getReactEmbeddableFactory = async < SerializedState extends object = object, - Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, - RuntimeState extends object = SerializedState + RuntimeState extends object = SerializedState, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi< + SerializedState, + RuntimeState + > >( key: string -): Promise> => { +): Promise> => { if (registry[key] === undefined) throw new Error( i18n.translate('embeddableApi.reactEmbeddable.factoryNotFoundError', { diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx index 8d8a632caec1fa..002328cf222740 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx @@ -38,8 +38,11 @@ const ON_STATE_CHANGE_DEBOUNCE = 100; */ export const ReactEmbeddableRenderer = < SerializedState extends object = object, - Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, RuntimeState extends object = SerializedState, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi< + SerializedState, + RuntimeState + >, ParentApi extends HasSerializedChildState = HasSerializedChildState >({ type, @@ -95,11 +98,11 @@ export const ReactEmbeddableRenderer = < */ return (async () => { const parentApi = getParentApi(); - const factory = await getReactEmbeddableFactory(type); + const factory = await getReactEmbeddableFactory(type); const subscriptions = new Subscription(); const setApi = ( - apiRegistration: SetReactEmbeddableApiRegistration + apiRegistration: SetReactEmbeddableApiRegistration ) => { const fullApi = { ...apiRegistration, @@ -115,12 +118,16 @@ export const ReactEmbeddableRenderer = < const buildEmbeddable = async () => { const { initialState, startStateDiffing } = await initializeReactEmbeddableState< SerializedState, - Api, - RuntimeState + RuntimeState, + Api >(uuid, factory, parentApi); const buildApi = ( - apiRegistration: BuildReactEmbeddableApiRegistration, + apiRegistration: BuildReactEmbeddableApiRegistration< + SerializedState, + RuntimeState, + Api + >, comparators: StateComparators ) => { if (onAnyStateChange) { @@ -160,7 +167,7 @@ export const ReactEmbeddableRenderer = < unsavedChanges, resetUnsavedChanges, snapshotRuntimeState, - } as unknown as SetReactEmbeddableApiRegistration); + } as unknown as SetReactEmbeddableApiRegistration); cleanupFunction.current = () => cleanup(); return fullApi; diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts index 605b8d20a7cd1d..ddfaf10953821c 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts @@ -29,11 +29,14 @@ import { DefaultEmbeddableApi, ReactEmbeddableFactory } from './types'; export const initializeReactEmbeddableState = async < SerializedState extends object = object, - Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, - RuntimeState extends object = SerializedState + RuntimeState extends object = SerializedState, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi< + SerializedState, + RuntimeState + > >( uuid: string, - factory: ReactEmbeddableFactory, + factory: ReactEmbeddableFactory, parentApi: HasSerializedChildState ) => { const lastSavedRuntimeState = await factory.deserializeState( diff --git a/src/plugins/embeddable/public/react_embeddable_system/types.ts b/src/plugins/embeddable/public/react_embeddable_system/types.ts index 8a05698934e9cb..cc4b9cf9b7976f 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/types.ts +++ b/src/plugins/embeddable/public/react_embeddable_system/types.ts @@ -41,7 +41,11 @@ export interface DefaultEmbeddableApi< */ export type SetReactEmbeddableApiRegistration< SerializedState extends object = object, - Api extends DefaultEmbeddableApi = DefaultEmbeddableApi + RuntimeState extends object = SerializedState, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi< + SerializedState, + RuntimeState + > > = Omit; /** @@ -50,9 +54,13 @@ export type SetReactEmbeddableApiRegistration< */ export type BuildReactEmbeddableApiRegistration< SerializedState extends object = object, - Api extends DefaultEmbeddableApi = DefaultEmbeddableApi + RuntimeState extends object = SerializedState, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi< + SerializedState, + RuntimeState + > > = Omit< - SetReactEmbeddableApiRegistration, + SetReactEmbeddableApiRegistration, 'unsavedChanges' | 'resetUnsavedChanges' | 'snapshotRuntimeState' >; @@ -65,8 +73,11 @@ export type BuildReactEmbeddableApiRegistration< **/ export interface ReactEmbeddableFactory< SerializedState extends object = object, - Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, - RuntimeState extends object = SerializedState + RuntimeState extends object = SerializedState, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi< + SerializedState, + RuntimeState + > > { /** * A unique key for the type of this embeddable. The React Embeddable Renderer will use this type @@ -101,12 +112,12 @@ export interface ReactEmbeddableFactory< * changes logic that the dashboard expects using the provided comparators */ buildApi: ( - apiRegistration: BuildReactEmbeddableApiRegistration, + apiRegistration: BuildReactEmbeddableApiRegistration, comparators: StateComparators ) => Api, uuid: string, parentApi: unknown | undefined, /** `setApi` should be used when the unsaved changes logic in `buildApi` is unnecessary */ - setApi: (api: SetReactEmbeddableApiRegistration) => Api + setApi: (api: SetReactEmbeddableApiRegistration) => Api ) => Promise<{ Component: React.FC<{}>; api: Api }>; } diff --git a/src/plugins/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx b/src/plugins/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx index d5b15122f70f19..2bbff60a50efe8 100644 --- a/src/plugins/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx +++ b/src/plugins/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx @@ -30,6 +30,7 @@ export const getImageEmbeddableFactory = ({ embeddableEnhanced?: EmbeddableEnhancedPluginStart; }) => { const imageEmbeddableFactory: ReactEmbeddableFactory< + ImageEmbeddableSerializedState, ImageEmbeddableSerializedState, ImageEmbeddableApi > = { diff --git a/x-pack/plugins/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx b/x-pack/plugins/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx index 5b8345dd28d39e..7e0e00b7ac02d3 100644 --- a/x-pack/plugins/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx +++ b/x-pack/plugins/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx @@ -68,8 +68,8 @@ export const getChangePointChartEmbeddableFactory = ( ) => { const factory: ReactEmbeddableFactory< ChangePointEmbeddableState, - ChangePointEmbeddableApi, - ChangePointEmbeddableRuntimeState + ChangePointEmbeddableRuntimeState, + ChangePointEmbeddableApi > = { type: EMBEDDABLE_CHANGE_POINT_CHART_TYPE, deserializeState: (state) => { diff --git a/x-pack/plugins/maps/public/lens/passive_map.tsx b/x-pack/plugins/maps/public/lens/passive_map.tsx index fc2a9c33937332..30a4b8013b8abb 100644 --- a/x-pack/plugins/maps/public/lens/passive_map.tsx +++ b/x-pack/plugins/maps/public/lens/passive_map.tsx @@ -12,7 +12,7 @@ import { ReactEmbeddableRenderer, ViewMode } from '@kbn/embeddable-plugin/public import type { LayerDescriptor } from '../../common/descriptor_types'; import { INITIAL_LOCATION, MAP_SAVED_OBJECT_TYPE } from '../../common'; import { createBasemapLayerDescriptor } from '../classes/layers/create_basemap_layer_descriptor'; -import { MapApi, MapSerializedState } from '../react_embeddable/types'; +import { MapApi, MapRuntimeState, MapSerializedState } from '../react_embeddable/types'; export interface Props { passiveLayer: LayerDescriptor; @@ -50,7 +50,7 @@ export function PassiveMap(props: Props) { return (
- + type={MAP_SAVED_OBJECT_TYPE} getParentApi={() => ({ getSerializedStateForChild: () => { diff --git a/x-pack/plugins/maps/public/react_embeddable/map_react_embeddable.tsx b/x-pack/plugins/maps/public/react_embeddable/map_react_embeddable.tsx index b8028caac41f82..415e3819cdadb7 100644 --- a/x-pack/plugins/maps/public/react_embeddable/map_react_embeddable.tsx +++ b/x-pack/plugins/maps/public/react_embeddable/map_react_embeddable.tsx @@ -22,7 +22,7 @@ import { BehaviorSubject } from 'rxjs'; import { apiPublishesSettings } from '@kbn/presentation-containers/interfaces/publishes_settings'; import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants'; import { inject } from '../../common/embeddable'; -import type { MapApi, MapSerializedState } from './types'; +import type { MapApi, MapRuntimeState, MapSerializedState } from './types'; import { SavedMap } from '../routes/map_page'; import { initializeReduxSync } from './initialize_redux_sync'; import { @@ -44,7 +44,11 @@ export function getControlledBy(id: string) { return `mapEmbeddablePanel${id}`; } -export const mapEmbeddableFactory: ReactEmbeddableFactory = { +export const mapEmbeddableFactory: ReactEmbeddableFactory< + MapSerializedState, + MapRuntimeState, + MapApi +> = { type: MAP_SAVED_OBJECT_TYPE, deserializeState: (state) => { return state.rawState diff --git a/x-pack/plugins/maps/public/react_embeddable/map_renderer.tsx b/x-pack/plugins/maps/public/react_embeddable/map_renderer.tsx index 27dc202e778b07..7701c7ebbe11b8 100644 --- a/x-pack/plugins/maps/public/react_embeddable/map_renderer.tsx +++ b/x-pack/plugins/maps/public/react_embeddable/map_renderer.tsx @@ -11,7 +11,7 @@ import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; import { useSearchApi } from '@kbn/presentation-publishing'; import type { LayerDescriptor, MapCenterAndZoom, MapSettings } from '../../common/descriptor_types'; import { createBasemapLayerDescriptor } from '../classes/layers/create_basemap_layer_descriptor'; -import { MapApi, MapSerializedState } from './types'; +import { MapApi, MapRuntimeState, MapSerializedState } from './types'; import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants'; import { RenderToolTipContent } from '../classes/tooltips/tooltip_property'; @@ -58,7 +58,7 @@ export function MapRenderer(props: Props) { return (
- + type={MAP_SAVED_OBJECT_TYPE} getParentApi={() => ({ ...searchApi, diff --git a/x-pack/plugins/maps/public/react_embeddable/types.ts b/x-pack/plugins/maps/public/react_embeddable/types.ts index c650c51b22ddce..f020e75723c6cd 100644 --- a/x-pack/plugins/maps/public/react_embeddable/types.ts +++ b/x-pack/plugins/maps/public/react_embeddable/types.ts @@ -58,6 +58,8 @@ export type MapSerializedState = SerializedTitles & tooltipRenderer?: RenderToolTipContent; }; +export type MapRuntimeState = MapSerializedState; + export type MapApi = DefaultEmbeddableApi & HasDynamicActions & Partial & diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx index 1dc792ffc44bf2..3f5afc4065e1f4 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx @@ -37,161 +37,164 @@ import { buildDataViewPublishingApi } from '../common/anomaly_detection_embeddab export const getAnomalyChartsReactEmbeddableFactory = ( getStartServices: StartServicesAccessor ) => { - const factory: ReactEmbeddableFactory = - { - type: ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, - deserializeState: (state) => state.rawState, - buildEmbeddable: async (state, buildApi, uuid, parentApi) => { - if (!apiHasExecutionContext(parentApi)) { - throw new Error('Parent API does not have execution context'); - } - const [coreStartServices, pluginsStartServices] = await getStartServices(); - const anomalyChartsDependencies = await getAnomalyChartsServiceDependencies( - coreStartServices, - pluginsStartServices - ); + const factory: ReactEmbeddableFactory< + AnomalyChartsEmbeddableState, + AnomalyChartsEmbeddableState, + AnomalyChartsEmbeddableApi + > = { + type: ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, + deserializeState: (state) => state.rawState, + buildEmbeddable: async (state, buildApi, uuid, parentApi) => { + if (!apiHasExecutionContext(parentApi)) { + throw new Error('Parent API does not have execution context'); + } + const [coreStartServices, pluginsStartServices] = await getStartServices(); + const anomalyChartsDependencies = await getAnomalyChartsServiceDependencies( + coreStartServices, + pluginsStartServices + ); - const [, , mlServices] = anomalyChartsDependencies; + const [, , mlServices] = anomalyChartsDependencies; - const subscriptions = new Subscription(); + const subscriptions = new Subscription(); - const { titlesApi, titleComparators, serializeTitles } = initializeTitles(state); - const { - api: timeRangeApi, - comparators: timeRangeComparators, - serialize: serializeTimeRange, - } = initializeTimeRange(state); + const { titlesApi, titleComparators, serializeTitles } = initializeTitles(state); + const { + api: timeRangeApi, + comparators: timeRangeComparators, + serialize: serializeTimeRange, + } = initializeTimeRange(state); - const { - anomalyChartsControlsApi, - dataLoadingApi, - serializeAnomalyChartsState, - anomalyChartsComparators, - onAnomalyChartsDestroy, - } = initializeAnomalyChartsControls(state, titlesApi, parentApi); + const { + anomalyChartsControlsApi, + dataLoadingApi, + serializeAnomalyChartsState, + anomalyChartsComparators, + onAnomalyChartsDestroy, + } = initializeAnomalyChartsControls(state, titlesApi, parentApi); - const api = buildApi( - { - isEditingEnabled: () => true, - getTypeDisplayName: () => - i18n.translate('xpack.ml.components.mlAnomalyExplorerEmbeddable.typeDisplayName', { - defaultMessage: 'anomaly charts', - }), - onEdit: async () => { - try { - const { resolveEmbeddableAnomalyChartsUserInput } = await import( - './anomaly_charts_setup_flyout' - ); - const result = await resolveEmbeddableAnomalyChartsUserInput( - coreStartServices, - pluginsStartServices, - parentApi, - uuid, - { - ...serializeTitles(), - ...serializeAnomalyChartsState(), - } - ); - anomalyChartsControlsApi.updateUserInput(result); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - return Promise.reject(); - } - }, - ...titlesApi, - ...timeRangeApi, - ...anomalyChartsControlsApi, - ...dataLoadingApi, - dataViews: buildDataViewPublishingApi( - { - anomalyDetectorService: mlServices.anomalyDetectorService, - dataViewsService: pluginsStartServices.data.dataViews, - }, - { jobIds: anomalyChartsControlsApi.jobIds$ }, - subscriptions - ), - serializeState: () => { - return { - rawState: { - timeRange: undefined, + const api = buildApi( + { + isEditingEnabled: () => true, + getTypeDisplayName: () => + i18n.translate('xpack.ml.components.mlAnomalyExplorerEmbeddable.typeDisplayName', { + defaultMessage: 'anomaly charts', + }), + onEdit: async () => { + try { + const { resolveEmbeddableAnomalyChartsUserInput } = await import( + './anomaly_charts_setup_flyout' + ); + const result = await resolveEmbeddableAnomalyChartsUserInput( + coreStartServices, + pluginsStartServices, + parentApi, + uuid, + { ...serializeTitles(), - ...serializeTimeRange(), ...serializeAnomalyChartsState(), - }, - references: [], - }; + } + ); + anomalyChartsControlsApi.updateUserInput(result); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + return Promise.reject(); + } + }, + ...titlesApi, + ...timeRangeApi, + ...anomalyChartsControlsApi, + ...dataLoadingApi, + dataViews: buildDataViewPublishingApi( + { + anomalyDetectorService: mlServices.anomalyDetectorService, + dataViewsService: pluginsStartServices.data.dataViews, }, + { jobIds: anomalyChartsControlsApi.jobIds$ }, + subscriptions + ), + serializeState: () => { + return { + rawState: { + timeRange: undefined, + ...serializeTitles(), + ...serializeTimeRange(), + ...serializeAnomalyChartsState(), + }, + references: [], + }; }, - { - ...timeRangeComparators, - ...titleComparators, - ...anomalyChartsComparators, - } - ); + }, + { + ...timeRangeComparators, + ...titleComparators, + ...anomalyChartsComparators, + } + ); - const appliedTimeRange$: Observable = fetch$(api).pipe( - map((fetchContext) => fetchContext.timeRange), - distinctUntilChanged(fastIsEqual) - ); + const appliedTimeRange$: Observable = fetch$(api).pipe( + map((fetchContext) => fetchContext.timeRange), + distinctUntilChanged(fastIsEqual) + ); - const { onRenderComplete, onLoading, onError } = dataLoadingApi; - const contextServices = { - mlServices: { - ...mlServices, - }, - ...coreStartServices, - ...pluginsStartServices, - }; + const { onRenderComplete, onLoading, onError } = dataLoadingApi; + const contextServices = { + mlServices: { + ...mlServices, + }, + ...coreStartServices, + ...pluginsStartServices, + }; - return { - api, - Component: () => { - if (!apiHasExecutionContext(parentApi)) { - throw new Error('Parent API does not have execution context'); - } + return { + api, + Component: () => { + if (!apiHasExecutionContext(parentApi)) { + throw new Error('Parent API does not have execution context'); + } - useReactEmbeddableExecutionContext( - coreStartServices.executionContext, - parentApi.executionContext, - ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, - uuid - ); + useReactEmbeddableExecutionContext( + coreStartServices.executionContext, + parentApi.executionContext, + ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, + uuid + ); - useUnmount(() => { - onAnomalyChartsDestroy(); - subscriptions.unsubscribe(); - }); - const { euiTheme } = useEuiTheme(); + useUnmount(() => { + onAnomalyChartsDestroy(); + subscriptions.unsubscribe(); + }); + const { euiTheme } = useEuiTheme(); - return ( - - -
- -
-
-
- ); - }, - }; - }, - }; + return ( + + +
+ +
+
+
+ ); + }, + }; + }, + }; return factory; }; diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx index 4765950b341f90..61a2fadeb6df84 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx @@ -97,7 +97,11 @@ describe('getAnomalySwimLaneEmbeddableFactory', () => { >; render( - + maybeId={'maybe_id'} type={ANOMALY_SWIMLANE_EMBEDDABLE_TYPE} onApiAvailable={onApiAvailable} diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx index c67c2ed157cda0..6de07c5db851e4 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx @@ -89,8 +89,8 @@ export const getAnomalySwimLaneEmbeddableFactory = ( ) => { const factory: ReactEmbeddableFactory< AnomalySwimLaneEmbeddableState, - AnomalySwimLaneEmbeddableApi, - AnomalySwimlaneRuntimeState + AnomalySwimlaneRuntimeState, + AnomalySwimLaneEmbeddableApi > = { type: ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, deserializeState: (state) => state.rawState, diff --git a/x-pack/plugins/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx b/x-pack/plugins/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx index 3fa630d7194e92..dcddb9f2d373e4 100644 --- a/x-pack/plugins/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx +++ b/x-pack/plugins/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx @@ -36,8 +36,8 @@ export const getSingleMetricViewerEmbeddableFactory = ( ) => { const factory: ReactEmbeddableFactory< SingleMetricViewerEmbeddableState, - SingleMetricViewerEmbeddableApi, - SingleMetricViewerRuntimeState + SingleMetricViewerRuntimeState, + SingleMetricViewerEmbeddableApi > = { type: ANOMALY_SINGLE_METRIC_VIEWER_EMBEDDABLE_TYPE, deserializeState: (state) => state.rawState, diff --git a/x-pack/plugins/ml/public/shared_components/anomaly_swim_lane.tsx b/x-pack/plugins/ml/public/shared_components/anomaly_swim_lane.tsx index b7748a753cc5c3..5c995d0ddcb653 100644 --- a/x-pack/plugins/ml/public/shared_components/anomaly_swim_lane.tsx +++ b/x-pack/plugins/ml/public/shared_components/anomaly_swim_lane.tsx @@ -116,7 +116,11 @@ export const AnomalySwimLane: FC = ({ ); return ( - + maybeId={id} type={ANOMALY_SWIMLANE_EMBEDDABLE_TYPE} getParentApi={() => parentApi} diff --git a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx index d6f2e43c724b22..6418799c4ad38a 100644 --- a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx @@ -19,6 +19,7 @@ export const APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE = export const getApmAlertingFailedTransactionsChartEmbeddableFactory = (deps: EmbeddableDeps) => { const factory: ReactEmbeddableFactory< + EmbeddableApmAlertingVizProps, EmbeddableApmAlertingVizProps, DefaultEmbeddableApi > = { diff --git a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx index f828a35a89d698..0795c821fc4657 100644 --- a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx @@ -18,6 +18,7 @@ export const APM_ALERTING_LATENCY_CHART_EMBEDDABLE = 'APM_ALERTING_LATENCY_CHART export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps) => { const factory: ReactEmbeddableFactory< + EmbeddableApmAlertingLatencyVizProps, EmbeddableApmAlertingLatencyVizProps, DefaultEmbeddableApi > = { diff --git a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx index 7ce986cd3b5bcc..6fe2135d8ec623 100644 --- a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx @@ -18,6 +18,7 @@ export const APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE = 'APM_ALERTING_THROUGHPUT export const getApmAlertingThroughputChartEmbeddableFactory = (deps: EmbeddableDeps) => { const factory: ReactEmbeddableFactory< + EmbeddableApmAlertingVizProps, EmbeddableApmAlertingVizProps, DefaultEmbeddableApi > = { diff --git a/x-pack/plugins/observability_solution/infra/public/components/log_stream/log_stream_react_embeddable.tsx b/x-pack/plugins/observability_solution/infra/public/components/log_stream/log_stream_react_embeddable.tsx index 313eb476c4ae5e..bbb2e09d8660a1 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/log_stream/log_stream_react_embeddable.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/log_stream/log_stream_react_embeddable.tsx @@ -24,7 +24,11 @@ import { useKibanaContextForPluginProvider } from '../../hooks/use_kibana'; import { InfraClientStartDeps, InfraClientStartExports } from '../../types'; export function getLogStreamEmbeddableFactory(services: Services) { - const factory: ReactEmbeddableFactory = { + const factory: ReactEmbeddableFactory< + LogStreamSerializedState, + LogStreamSerializedState, + LogStreamApi + > = { type: LOG_STREAM_EMBEDDABLE, deserializeState: (state) => state.rawState, buildEmbeddable: async (state, buildApi) => { diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx index 7472c43253454b..b70e1d8e4c40a2 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx @@ -33,7 +33,11 @@ export const getAlertsPanelTitle = () => }); export function getAlertsEmbeddableFactory(deps: SloEmbeddableDeps, kibanaVersion: string) { - const factory: ReactEmbeddableFactory = { + const factory: ReactEmbeddableFactory< + SloAlertsEmbeddableState, + SloAlertsEmbeddableState, + SloAlertsApi + > = { type: SLO_ALERTS_EMBEDDABLE_ID, deserializeState: (state) => { return state.rawState as SloAlertsEmbeddableState; diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx index 63ebb3fb372050..6d01995fb81911 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx @@ -28,7 +28,11 @@ export const getErrorBudgetPanelTitle = () => const queryClient = new QueryClient(); export const getErrorBudgetEmbeddableFactory = (deps: SloEmbeddableDeps) => { - const factory: ReactEmbeddableFactory = { + const factory: ReactEmbeddableFactory< + SloErrorBudgetEmbeddableState, + SloErrorBudgetEmbeddableState, + ErrorBudgetApi + > = { type: SLO_ERROR_BUDGET_ID, deserializeState: (state) => { return state.rawState as SloErrorBudgetEmbeddableState; diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx index 33252386c0e81a..861909b040e9a5 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx @@ -36,7 +36,11 @@ export const getOverviewPanelTitle = () => defaultMessage: 'SLO Overview', }); export const getOverviewEmbeddableFactory = (deps: SloEmbeddableDeps) => { - const factory: ReactEmbeddableFactory = { + const factory: ReactEmbeddableFactory< + SloOverviewEmbeddableState, + SloOverviewEmbeddableState, + SloOverviewApi + > = { type: SLO_OVERVIEW_EMBEDDABLE_ID, deserializeState: (state) => { return state.rawState as SloOverviewEmbeddableState; From c14a56e79a4cfaab4fea59768675b16bd6b24b2d Mon Sep 17 00:00:00 2001 From: Sid Date: Wed, 19 Jun 2024 16:17:41 +0200 Subject: [PATCH 095/123] Upgrade `ws@8.17.0` -> `ws@8.17.1` (#186362) Update ws production dependency to use 8.17.1. WS changelog: https://github.com/websockets/ws/releases/tag/8.17.1 --- yarn.lock | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index d1dec3cae024ad..d59f566dc8627b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32310,15 +32310,20 @@ write-file-atomic@^4.0.1, write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@8.17.0, ws@>=8.16.0, ws@^8.2.3, ws@^8.4.2, ws@^8.9.0: +ws@8.17.0: version "8.17.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.0.tgz#d145d18eca2ed25aaf791a183903f7be5e295fea" integrity sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow== +ws@>=8.16.0, ws@^8.2.3, ws@^8.4.2, ws@^8.9.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + ws@^7.3.1, ws@^7.4.2: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== x-default-browser@^0.4.0: version "0.4.0" From c2986d9a6f09fd7644695ad72f46e7acfec964a3 Mon Sep 17 00:00:00 2001 From: Alex Szabo Date: Wed, 19 Jun 2024 16:55:18 +0200 Subject: [PATCH 096/123] [CI] Fix missing test failure annotations (#186446) ## Summary rename `SLACK_NOTIFICATIONS_ENABLED` => `ELASTIC_SLACK_NOTIFICATIONS_ENABLED` to follow up on elastic-wide buildkite changes. This should re-enable test failure listing on the slack errors we post. --- .buildkite/pipeline-utils/test-failures/annotate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/pipeline-utils/test-failures/annotate.ts b/.buildkite/pipeline-utils/test-failures/annotate.ts index c49128ae3c62b8..39aa2d36b9ddbd 100644 --- a/.buildkite/pipeline-utils/test-failures/annotate.ts +++ b/.buildkite/pipeline-utils/test-failures/annotate.ts @@ -177,7 +177,7 @@ export const annotateTestFailures = async () => { ); } - if (process.env.SLACK_NOTIFICATIONS_ENABLED === 'true') { + if (process.env.ELASTIC_SLACK_NOTIFICATIONS_ENABLED === 'true') { buildkite.setMetadata( 'slack:test_failures:body', getSlackMessage(failures, failureHtmlArtifacts) From 39ac3e1ceac31ef8cb52b8842e77103905973d9f Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Wed, 19 Jun 2024 10:59:52 -0400 Subject: [PATCH 097/123] [Fleet] Add retry when retrieving agent version (#186459) --- .../inputs_with_standalone_docker_agent.ts | 3 +-- x-pack/test/fleet_cypress/artifact_manager.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts b/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts index 64a9077b916d98..ca1d8c0c3f312c 100644 --- a/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts +++ b/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts @@ -25,8 +25,7 @@ export default function (providerContext: FtrProviderContext) { const config = getService('config'); const log = getService('log'); - // FLAKY: https://github.com/elastic/kibana/issues/184681 - describe.skip('inputs_with_standalone_docker_agent', () => { + describe('inputs_with_standalone_docker_agent', () => { skipIfNoDockerRegistry(providerContext); let apiKey: string; let agent: AgentProcess; diff --git a/x-pack/test/fleet_cypress/artifact_manager.ts b/x-pack/test/fleet_cypress/artifact_manager.ts index 17ba9b0a5517d6..0fe6609f28efc7 100644 --- a/x-pack/test/fleet_cypress/artifact_manager.ts +++ b/x-pack/test/fleet_cypress/artifact_manager.ts @@ -7,8 +7,14 @@ import axios from 'axios'; import { last } from 'lodash'; +import pRetry from 'p-retry'; + +const DEFAULT_VERSION = '8.15.0-SNAPSHOT'; export async function getLatestVersion(): Promise { - const response: any = await axios('https://artifacts-api.elastic.co/v1/versions'); - return last(response.data.versions as string[]) || '8.1.0-SNAPSHOT'; + return pRetry(() => axios('https://artifacts-api.elastic.co/v1/versions'), { + maxRetryTime: 60 * 1000, // 1 minute + }) + .then((response) => last(response.data.versions as string[]) || DEFAULT_VERSION) + .catch(() => DEFAULT_VERSION); } From 6e905c24dde2dff938f3a9cdc7e17b7455e3a081 Mon Sep 17 00:00:00 2001 From: Cristina Amico Date: Wed, 19 Jun 2024 17:05:51 +0200 Subject: [PATCH 098/123] [Fleet] Adjust delete package policy warning for multiple agent policies (#186316) Fixes https://github.com/elastic/kibana/issues/182218 ## Summary Add a warning to integration policy delete action in case of multiple agent policies. ![Screenshot 2024-06-19 at 10 17 52](https://github.com/elastic/kibana/assets/16084106/dacca9f8-afd1-4290-bf6e-ea8cb468a5b7) ![Screenshot 2024-06-19 at 10 17 56](https://github.com/elastic/kibana/assets/16084106/6c2322c1-e9a6-4028-9ea4-e84659445e19) ## Testing - Enable `enableReusableIntegrationPolicies` - Get an integration that has multiple agent policies and navigate to `integrations/detail/{pkgName-Version}/policies` - From the actions on the rigth, select `Delete integration` - A warning with `This integration is shared by multiple agent policies.` should be displayed ### Checklist - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../package_policies_table.tsx | 2 +- .../detail/policies/package_policies.tsx | 2 +- .../package_policy_actions_menu.test.tsx | 137 ++++++++++-------- .../package_policy_actions_menu.tsx | 7 +- .../package_policy_delete_provider.tsx | 100 +++++++++---- 5 files changed, 155 insertions(+), 93 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx index fd9a27ed66f013..a121c797757d7c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx @@ -249,7 +249,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ render: (packagePolicy: InMemoryPackagePolicy) => { return canWriteIntegrationPolicies ? ( = {}): AgentPolicy { - return { - id: 'some-uuid1', - namespace: 'default', - monitoring_enabled: [], - name: 'Test Policy', - description: '', - is_preconfigured: false, - status: 'active', - is_managed: false, - revision: 1, - updated_at: '', - updated_by: 'elastic', - package_policies: [], - is_protected: false, - ...props, - }; +function createMockAgentPolicies(props: Partial = {}): AgentPolicy[] { + return [ + { + id: 'some-uuid1', + namespace: 'default', + monitoring_enabled: [], + name: 'Test Policy', + description: '', + is_preconfigured: false, + status: 'active', + is_managed: false, + revision: 1, + updated_at: '', + updated_by: 'elastic', + package_policies: [], + is_protected: false, + ...props, + }, + ]; } function createMockPackagePolicy( @@ -81,60 +85,67 @@ function createMockPackagePolicy( ...props, }; } +describe('PackagePolicyActionsMenu', () => { + beforeAll(() => { + jest.spyOn(ExperimentalFeaturesService, 'get').mockReturnValue({ + enableReusableIntegrationPolicies: false, + } as any); + }); -test('Should disable upgrade button if package does not have upgrade', async () => { - const agentPolicy = createMockAgentPolicy(); - const packagePolicy = createMockPackagePolicy({ hasUpgrade: false }); - const { utils } = renderMenu({ agentPolicy, packagePolicy }); - await act(async () => { - const upgradeButton = utils.getByText('Upgrade integration policy').closest('button'); - expect(upgradeButton).toBeDisabled(); + it('Should disable upgrade button if package does not have upgrade', async () => { + const agentPolicies = createMockAgentPolicies(); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: false }); + const { utils } = renderMenu({ agentPolicies, packagePolicy }); + await act(async () => { + const upgradeButton = utils.getByText('Upgrade integration policy').closest('button'); + expect(upgradeButton).toBeDisabled(); + }); }); -}); -test('Should enable upgrade button if package has upgrade', async () => { - const agentPolicy = createMockAgentPolicy(); - const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); - const { utils } = renderMenu({ agentPolicy, packagePolicy }); + it('Should enable upgrade button if package has upgrade', async () => { + const agentPolicies = createMockAgentPolicies(); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); + const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { - const upgradeButton = utils.getByTestId('PackagePolicyActionsUpgradeItem'); - expect(upgradeButton).not.toBeDisabled(); + await act(async () => { + const upgradeButton = utils.getByTestId('PackagePolicyActionsUpgradeItem'); + expect(upgradeButton).not.toBeDisabled(); + }); }); -}); -test('Should not be able to delete integration from a managed policy', async () => { - const agentPolicy = createMockAgentPolicy({ is_managed: true }); - const packagePolicy = createMockPackagePolicy(); - const { utils } = renderMenu({ agentPolicy, packagePolicy }); - await act(async () => { - expect(utils.queryByText('Delete integration')).toBeNull(); + it('Should not be able to delete integration from a managed policy', async () => { + const agentPolicies = createMockAgentPolicies({ is_managed: true }); + const packagePolicy = createMockPackagePolicy(); + const { utils } = renderMenu({ agentPolicies, packagePolicy }); + await act(async () => { + expect(utils.queryByText('Delete integration')).toBeNull(); + }); }); -}); -test('Should be able to delete integration from a non-managed policy', async () => { - const agentPolicy = createMockAgentPolicy({ is_managed: false }); - const packagePolicy = createMockPackagePolicy(); - const { utils } = renderMenu({ agentPolicy, packagePolicy }); - await act(async () => { - expect(utils.queryByText('Delete integration')).not.toBeNull(); + it('Should be able to delete integration from a non-managed policy', async () => { + const agentPolicies = createMockAgentPolicies({ is_managed: false }); + const packagePolicy = createMockPackagePolicy(); + const { utils } = renderMenu({ agentPolicies, packagePolicy }); + await act(async () => { + expect(utils.queryByText('Delete integration')).not.toBeNull(); + }); }); -}); -test('Should show add button if the policy is not managed and showAddAgent=true', async () => { - const agentPolicy = createMockAgentPolicy(); - const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); - const { utils } = renderMenu({ agentPolicy, packagePolicy, showAddAgent: true }); - await act(async () => { - expect(utils.queryByText('Add agent')).not.toBeNull(); + it('Should show add button if the policy is not managed and showAddAgent=true', async () => { + const agentPolicies = createMockAgentPolicies(); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); + const { utils } = renderMenu({ agentPolicies, packagePolicy, showAddAgent: true }); + await act(async () => { + expect(utils.queryByText('Add agent')).not.toBeNull(); + }); }); -}); -test('Should not show add button if the policy is managed and showAddAgent=true', async () => { - const agentPolicy = createMockAgentPolicy({ is_managed: true }); - const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); - const { utils } = renderMenu({ agentPolicy, packagePolicy, showAddAgent: true }); - await act(async () => { - expect(utils.queryByText('Add agent')).toBeNull(); + it('Should not show add button if the policy is managed and showAddAgent=true', async () => { + const agentPolicies = createMockAgentPolicies({ is_managed: true }); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); + const { utils } = renderMenu({ agentPolicies, packagePolicy, showAddAgent: true }); + await act(async () => { + expect(utils.queryByText('Add agent')).toBeNull(); + }); }); }); diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx index 23ae673ad892ad..a8839e23a99f96 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx @@ -19,14 +19,14 @@ import { DangerEuiContextMenuItem } from './danger_eui_context_menu_item'; import { PackagePolicyDeleteProvider } from './package_policy_delete_provider'; export const PackagePolicyActionsMenu: React.FunctionComponent<{ - agentPolicy?: AgentPolicy; + agentPolicies: AgentPolicy[]; packagePolicy: InMemoryPackagePolicy; showAddAgent?: boolean; defaultIsOpen?: boolean; upgradePackagePolicyHref?: string; from?: 'fleet-policy-list' | undefined; }> = ({ - agentPolicy, + agentPolicies, packagePolicy, showAddAgent, upgradePackagePolicyHref, @@ -37,6 +37,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ const { getHref } = useLink(); const authz = useAuthz(); + const agentPolicy = agentPolicies.length > 0 ? agentPolicies[0] : undefined; // TODO: handle multiple agent policies const canWriteIntegrationPolicies = authz.integrations.writeIntegrationPolicies; const isFleetServerPolicy = agentPolicy && policyHasFleetServer(agentPolicy); @@ -126,7 +127,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ ? DangerEuiContextMenuItem : EuiContextMenuItem; menuItems.push( - + {(deletePackagePoliciesPrompt) => { return ( React.ReactElement; } @@ -27,7 +29,7 @@ export type DeletePackagePoliciesPrompt = ( type OnSuccessCallback = (packagePoliciesDeleted: string[]) => void; export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ - agentPolicy, + agentPolicies, children, }) => { const { notifications } = useStartServices(); @@ -40,27 +42,30 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ const [agentsCount, setAgentsCount] = useState(0); const [isLoading, setIsLoading] = useState(false); const onSuccessCallback = useRef(null); + const { enableReusableIntegrationPolicies } = ExperimentalFeaturesService.get(); + + const hasMultipleAgentPolicies = + enableReusableIntegrationPolicies && agentPolicies && agentPolicies.length > 1; const fetchAgentsCount = useMemo( () => async () => { - if (isLoadingAgentsCount || !isFleetEnabled || !agentPolicy) { + if (isLoadingAgentsCount || !isFleetEnabled || !agentPolicies) { return; } setIsLoadingAgentsCount(true); - const { data } = await sendRequest<{ total: number }>({ - path: AGENT_API_ROUTES.LIST_PATTERN, - method: 'get', - query: { - page: 1, - perPage: 1, - kuery: `${AGENTS_PREFIX}.policy_id : ${agentPolicy.id}`, - }, - version: API_VERSIONS.public.v1, + + const kuery = `(${agentPolicies + .map((policy) => `${AGENTS_PREFIX}.policy_id:"${policy.id}"`) + .join(' or ')})`; + + const request = await sendGetAgents({ + kuery, + showInactive: false, }); - setAgentsCount(data?.total || 0); + setAgentsCount(request.data?.total || 0); setIsLoadingAgentsCount(false); }, - [agentPolicy, isFleetEnabled, isLoadingAgentsCount] + [agentPolicies, isFleetEnabled, isLoadingAgentsCount] ); const deletePackagePoliciesPrompt = useMemo( @@ -87,6 +92,11 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ [] ); + const agentPoliciesNamesList = useMemo( + () => agentPolicies?.map((p) => p.name).join(', '), + [agentPolicies] + ); + const deletePackagePolicies = useMemo( () => async () => { setIsLoading(true); @@ -185,8 +195,23 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ id="xpack.fleet.deletePackagePolicy.confirmModal.loadingAgentsCountMessage" defaultMessage="Checking affected agents…" /> - ) : agentsCount ? ( + ) : agentsCount && agentPolicies ? ( <> + {hasMultipleAgentPolicies && ( + <> + + } + /> + + + )} = ({ /> } > - {agentPolicy?.name}, - }} - /> + {hasMultipleAgentPolicies ? ( + + } + position="top" + /> + ), + }} + /> + ) : ( + {agentPolicies[0]?.name}, + }} + /> + )} From 37ca5c6bd952378b96beb5974bc557da718682b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Wed, 19 Jun 2024 16:18:13 +0100 Subject: [PATCH 099/123] [Spaces] Add solution view select in UI (#186178) --- .buildkite/ftr_configs.yml | 1 + x-pack/plugins/spaces/kibana.jsonc | 3 +- x-pack/plugins/spaces/public/constants.ts | 2 + .../customize_space.test.tsx.snap | 1 + .../customize_space/customize_space.tsx | 2 +- .../edit_space/manage_space_page.test.tsx | 90 ++++++++++- .../edit_space/manage_space_page.tsx | 54 +++++-- .../section_panel/section_panel.tsx | 3 +- .../edit_space/solution_view/index.ts | 8 + .../solution_view/solution_view.tsx | 153 ++++++++++++++++++ .../management/spaces_management_app.test.tsx | 4 +- .../management/spaces_management_app.tsx | 26 ++- x-pack/plugins/spaces/public/plugin.tsx | 5 + x-pack/plugins/spaces/tsconfig.json | 1 + .../apps/spaces/create_edit_space.ts | 36 +++++ x-pack/test/functional/apps/spaces/index.ts | 1 + .../solution_view_flag_enabled/config.ts | 31 ++++ .../create_edit_space.ts | 69 ++++++++ .../solution_view_flag_enabled/index.ts | 14 ++ .../page_objects/space_selector_page.ts | 21 +++ 20 files changed, 506 insertions(+), 19 deletions(-) create mode 100644 x-pack/plugins/spaces/public/management/edit_space/solution_view/index.ts create mode 100644 x-pack/plugins/spaces/public/management/edit_space/solution_view/solution_view.tsx create mode 100644 x-pack/test/functional/apps/spaces/create_edit_space.ts create mode 100644 x-pack/test/functional/apps/spaces/solution_view_flag_enabled/config.ts create mode 100644 x-pack/test/functional/apps/spaces/solution_view_flag_enabled/create_edit_space.ts create mode 100644 x-pack/test/functional/apps/spaces/solution_view_flag_enabled/index.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index 83ae94ada8d065..c12bcf333dc08a 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -326,6 +326,7 @@ enabled: - x-pack/test/functional/apps/search_playground/config.ts - x-pack/test/functional/apps/snapshot_restore/config.ts - x-pack/test/functional/apps/spaces/config.ts + - x-pack/test/functional/apps/spaces/solution_view_flag_enabled/config.ts - x-pack/test/functional/apps/status_page/config.ts - x-pack/test/functional/apps/transform/creation/index_pattern/config.ts - x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/config.ts diff --git a/x-pack/plugins/spaces/kibana.jsonc b/x-pack/plugins/spaces/kibana.jsonc index 3b1555b52fcfd4..3c323141684176 100644 --- a/x-pack/plugins/spaces/kibana.jsonc +++ b/x-pack/plugins/spaces/kibana.jsonc @@ -19,7 +19,8 @@ "home", "management", "usageCollection", - "cloud" + "cloud", + "cloudExperiments" ], "requiredBundles": [ "esUiShared", diff --git a/x-pack/plugins/spaces/public/constants.ts b/x-pack/plugins/spaces/public/constants.ts index 64781228d4f434..27c6f04225d4fb 100644 --- a/x-pack/plugins/spaces/public/constants.ts +++ b/x-pack/plugins/spaces/public/constants.ts @@ -22,3 +22,5 @@ export const getSpacesFeatureDescription = () => { export const DEFAULT_OBJECT_NOUN = i18n.translate('xpack.spaces.shareToSpace.objectNoun', { defaultMessage: 'object', }); + +export const SOLUTION_NAV_FEATURE_FLAG_NAME = 'solutionNavEnabled'; diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space.test.tsx.snap index c799b56e7f7aee..31de1c9ea55e9d 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space.test.tsx.snap @@ -2,6 +2,7 @@ exports[`renders correctly 1`] = ` { }); return ( - + diff --git a/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.test.tsx index c95e4e4363dee5..68e8421449cf85 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.test.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.test.tsx @@ -10,12 +10,13 @@ import { EuiButton } from '@elastic/eui'; import { waitFor } from '@testing-library/react'; import type { ReactWrapper } from 'enzyme'; import React from 'react'; +import { of } from 'rxjs'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; import { notificationServiceMock, scopedHistoryMock } from '@kbn/core/public/mocks'; import { KibanaFeature } from '@kbn/features-plugin/public'; import { featuresPluginMock } from '@kbn/features-plugin/public/mocks'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; +import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; import { ConfirmAlterActiveSpaceModal } from './confirm_alter_active_space_modal'; import { EnabledFeatures } from './enabled_features'; @@ -105,6 +106,93 @@ describe('ManageSpacePage', () => { }); }); + it('shows solution view select when enabled', async () => { + const spacesManager = spacesManagerMock.create(); + spacesManager.createSpace = jest.fn(spacesManager.createSpace); + spacesManager.getActiveSpace = jest.fn().mockResolvedValue(space); + + const wrapper = mountWithIntl( + + ); + + await waitFor(() => { + wrapper.update(); + expect(wrapper.find('input[name="name"]')).toHaveLength(1); + }); + + expect(findTestSubject(wrapper, 'navigationPanel')).toHaveLength(1); + }); + + it('hides solution view select when not enabled or undefined', async () => { + const spacesManager = spacesManagerMock.create(); + spacesManager.createSpace = jest.fn(spacesManager.createSpace); + spacesManager.getActiveSpace = jest.fn().mockResolvedValue(space); + + { + const wrapper = mountWithIntl( + + ); + + await waitFor(() => { + wrapper.update(); + expect(wrapper.find('input[name="name"]')).toHaveLength(1); + }); + + expect(findTestSubject(wrapper, 'navigationPanel')).toHaveLength(0); + } + + { + const wrapper = mountWithIntl( + + ); + + await waitFor(() => { + wrapper.update(); + expect(wrapper.find('input[name="name"]')).toHaveLength(1); + }); + + expect(findTestSubject(wrapper, 'navigationPanel')).toHaveLength(0); + } + }); + it('shows feature visibility controls when allowed', async () => { const spacesManager = spacesManagerMock.create(); spacesManager.createSpace = jest.fn(spacesManager.createSpace); diff --git a/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.tsx b/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.tsx index fbba203f8e060c..8ea38d4fcc316a 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.tsx @@ -18,6 +18,7 @@ import { } from '@elastic/eui'; import { difference } from 'lodash'; import React, { Component } from 'react'; +import type { Observable, Subscription } from 'rxjs'; import type { Capabilities, NotificationsStart, ScopedHistory } from '@kbn/core/public'; import { SectionLoading } from '@kbn/es-ui-shared-plugin/public'; @@ -29,6 +30,7 @@ import { ConfirmAlterActiveSpaceModal } from './confirm_alter_active_space_modal import { CustomizeSpace } from './customize_space'; import { DeleteSpacesButton } from './delete_spaces_button'; import { EnabledFeatures } from './enabled_features'; +import { SolutionView } from './solution_view'; import type { Space } from '../../../common'; import { isReservedSpace } from '../../../common'; import { getSpacesFeatureDescription } from '../../constants'; @@ -54,6 +56,7 @@ interface Props { capabilities: Capabilities; history: ScopedHistory; allowFeatureVisibility: boolean; + isSolutionNavEnabled$?: Observable; } interface State { @@ -67,10 +70,13 @@ interface State { isInvalid: boolean; error?: string; }; + isSolutionNavEnabled: boolean; } export class ManageSpacePage extends Component { private readonly validator: SpaceValidator; + private initialSpaceState: State['space'] | null = null; + private subscription: Subscription | null = null; constructor(props: Props) { super(props); @@ -83,6 +89,7 @@ export class ManageSpacePage extends Component { color: getSpaceColor({}), }, features: [], + isSolutionNavEnabled: false, }; } @@ -107,6 +114,12 @@ export class ManageSpacePage extends Component { }), }); } + + if (this.props.isSolutionNavEnabled$) { + this.subscription = this.props.isSolutionNavEnabled$.subscribe((isEnabled) => { + this.setState({ isSolutionNavEnabled: isEnabled }); + }); + } } public async componentDidUpdate(previousProps: Props) { @@ -115,6 +128,12 @@ export class ManageSpacePage extends Component { } } + public componentWillUnmount() { + if (this.subscription) { + this.subscription.unsubscribe(); + } + } + public render() { if (!this.props.capabilities.spaces.manage) { return ( @@ -161,6 +180,13 @@ export class ManageSpacePage extends Component { validator={this.validator} /> + {this.state.isSolutionNavEnabled && ( + <> + + + + )} + {this.props.allowFeatureVisibility && ( <> @@ -298,8 +324,10 @@ export class ManageSpacePage extends Component { const haveDisabledFeaturesChanged = space.disabledFeatures.length !== originalSpace.disabledFeatures.length || difference(space.disabledFeatures, originalSpace.disabledFeatures).length > 0; + const hasSolutionViewChanged = + this.state.space.solution !== this.initialSpaceState?.solution; - if (editingActiveSpace && haveDisabledFeaturesChanged) { + if (editingActiveSpace && (haveDisabledFeaturesChanged || hasSolutionViewChanged)) { this.setState({ showAlteringActiveSpaceDialog: true, }); @@ -326,17 +354,19 @@ export class ManageSpacePage extends Component { onLoadSpace(space); } + this.initialSpaceState = { + ...space, + avatarType: space.imageUrl ? 'image' : 'initials', + initials: space.initials || getSpaceInitials(space), + color: space.color || getSpaceColor(space), + customIdentifier: false, + customAvatarInitials: + !!space.initials && getSpaceInitials({ name: space.name }) !== space.initials, + customAvatarColor: !!space.color && getSpaceColor({ name: space.name }) !== space.color, + }; + this.setState({ - space: { - ...space, - avatarType: space.imageUrl ? 'image' : 'initials', - initials: space.initials || getSpaceInitials(space), - color: space.color || getSpaceColor(space), - customIdentifier: false, - customAvatarInitials: - !!space.initials && getSpaceInitials({ name: space.name }) !== space.initials, - customAvatarColor: !!space.color && getSpaceColor({ name: space.name }) !== space.color, - }, + space: { ...this.initialSpaceState }, features, originalSpace: space, isLoading: false, @@ -369,6 +399,7 @@ export class ManageSpacePage extends Component { disabledFeatures = [], imageUrl, avatarType, + solution, } = this.state.space; const params = { @@ -379,6 +410,7 @@ export class ManageSpacePage extends Component { color: color ? hsvToHex(hexToHsv(color)).toUpperCase() : color, // Convert 3 digit hex codes to 6 digits since Spaces API requires 6 digits disabledFeatures, imageUrl: avatarType === 'image' ? imageUrl : '', + solution, }; let action; diff --git a/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.tsx b/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.tsx index 4ffa5ae9de2ea5..3d07aaabfd6b36 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/section_panel/section_panel.tsx @@ -13,12 +13,13 @@ import React, { Component, Fragment } from 'react'; interface Props { iconType?: IconType; title: string | ReactNode; + dataTestSubj?: string; } export class SectionPanel extends Component { public render() { return ( - + {this.getTitle()} {this.getForm()} diff --git a/x-pack/plugins/spaces/public/management/edit_space/solution_view/index.ts b/x-pack/plugins/spaces/public/management/edit_space/solution_view/index.ts new file mode 100644 index 00000000000000..0aabb34537273e --- /dev/null +++ b/x-pack/plugins/spaces/public/management/edit_space/solution_view/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 { SolutionView } from './solution_view'; diff --git a/x-pack/plugins/spaces/public/management/edit_space/solution_view/solution_view.tsx b/x-pack/plugins/spaces/public/management/edit_space/solution_view/solution_view.tsx new file mode 100644 index 00000000000000..0a6dc317161f29 --- /dev/null +++ b/x-pack/plugins/spaces/public/management/edit_space/solution_view/solution_view.tsx @@ -0,0 +1,153 @@ +/* + * 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 { EuiSuperSelectOption, EuiThemeComputed } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiIcon, + EuiSpacer, + EuiSuperSelect, + EuiText, + EuiTitle, + useEuiTheme, +} from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React from 'react'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import type { Space } from '../../../../common'; +import { SectionPanel } from '../section_panel'; + +type SolutionView = Space['solution']; + +const getOptions = ({ size }: EuiThemeComputed): Array> => { + const iconCss = { marginRight: size.m }; + + return [ + { + value: 'es', + inputDisplay: ( + <> + + {i18n.translate( + 'xpack.spaces.management.manageSpacePage.solutionViewSelect.searchOptionLabel', + { + defaultMessage: 'Search', + } + )} + + ), + 'data-test-subj': 'solutionViewEsOption', + }, + { + value: 'oblt', + inputDisplay: ( + <> + + {i18n.translate( + 'xpack.spaces.management.manageSpacePage.solutionViewSelect.obltOptionLabel', + { + defaultMessage: 'Observability', + } + )} + + ), + 'data-test-subj': 'solutionViewObltOption', + }, + { + value: 'security', + inputDisplay: ( + <> + + {i18n.translate( + 'xpack.spaces.management.manageSpacePage.solutionViewSelect.securityOptionLabel', + { + defaultMessage: 'Security', + } + )} + + ), + 'data-test-subj': 'solutionViewSecurityOption', + }, + { + value: 'classic', + inputDisplay: ( + <> + + {i18n.translate( + 'xpack.spaces.management.manageSpacePage.solutionViewSelect.classicOptionLabel', + { + defaultMessage: 'Classic', + } + )} + + ), + 'data-test-subj': 'solutionViewClassicOption', + }, + ]; +}; + +interface Props { + space: Partial; + onChange: (space: Partial) => void; +} + +export const SolutionView: FunctionComponent = ({ space, onChange }) => { + const { euiTheme } = useEuiTheme(); + + return ( + + + + +

+ +

+
+ + +

+ +

+
+
+ + + { + onChange({ ...space, solution }); + }} + /> + + +
+
+ ); +}; diff --git a/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx b/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx index 89e1fc01d493e4..b29d13bbd51a2d 100644 --- a/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_management_app.test.tsx @@ -125,7 +125,7 @@ describe('spacesManagementApp', () => { css="You have tried to stringify object returned from \`css\` function. It isn't supposed to be used directly (e.g. as value of the \`className\` prop), but rather handed to emotion so it can handle it (e.g. as value of \`css\` prop)." data-test-subj="kbnRedirectAppLink" > - Spaces Edit Page: {"capabilities":{"catalogue":{},"management":{},"navLinks":{}},"notifications":{"toasts":{}},"spacesManager":{"onActiveSpaceChange$":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/create","search":"","hash":""}},"allowFeatureVisibility":true} + Spaces Edit Page: {"capabilities":{"catalogue":{},"management":{},"navLinks":{}},"notifications":{"toasts":{}},"spacesManager":{"onActiveSpaceChange$":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/create","search":"","hash":""}},"allowFeatureVisibility":true,"isSolutionNavEnabled$":{}}
`); @@ -158,7 +158,7 @@ describe('spacesManagementApp', () => { css="You have tried to stringify object returned from \`css\` function. It isn't supposed to be used directly (e.g. as value of the \`className\` prop), but rather handed to emotion so it can handle it (e.g. as value of \`css\` prop)." data-test-subj="kbnRedirectAppLink" > - Spaces Edit Page: {"capabilities":{"catalogue":{},"management":{},"navLinks":{}},"notifications":{"toasts":{}},"spacesManager":{"onActiveSpaceChange$":{}},"spaceId":"some-space","history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/some-space","search":"","hash":""}},"allowFeatureVisibility":true} + Spaces Edit Page: {"capabilities":{"catalogue":{},"management":{},"navLinks":{}},"notifications":{"toasts":{}},"spacesManager":{"onActiveSpaceChange$":{}},"spaceId":"some-space","history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/some-space","search":"","hash":""}},"allowFeatureVisibility":true,"isSolutionNavEnabled$":{}} `); diff --git a/x-pack/plugins/spaces/public/management/spaces_management_app.tsx b/x-pack/plugins/spaces/public/management/spaces_management_app.tsx index fe6776b33f9202..eafefd93f44645 100644 --- a/x-pack/plugins/spaces/public/management/spaces_management_app.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_management_app.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { useParams } from 'react-router-dom'; +import { from, of, shareReplay } from 'rxjs'; import type { StartServicesAccessor } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; @@ -20,6 +21,7 @@ import { Route, Router, Routes } from '@kbn/shared-ux-router'; import type { Space } from '../../common'; import type { ConfigType } from '../config'; +import { SOLUTION_NAV_FEATURE_FLAG_NAME } from '../constants'; import type { PluginsStart } from '../plugin'; import type { SpacesManager } from '../spaces_manager'; @@ -43,8 +45,15 @@ export const spacesManagementApp = Object.freeze({ title, async mount({ element, setBreadcrumbs, history }) { - const [[coreStart, { features }], { SpacesGridPage }, { ManageSpacePage }] = - await Promise.all([getStartServices(), import('./spaces_grid'), import('./edit_space')]); + const [ + [coreStart, { features, cloud, cloudExperiments }], + { SpacesGridPage }, + { ManageSpacePage }, + ] = await Promise.all([ + getStartServices(), + import('./spaces_grid'), + import('./edit_space'), + ]); const spacesFirstBreadcrumb = { text: title, @@ -54,6 +63,17 @@ export const spacesManagementApp = Object.freeze({ chrome.docTitle.change(title); + const onCloud = Boolean(cloud?.isCloudEnabled); + const isSolutionNavEnabled$ = + // Only available on Cloud and if the Launch Darkly flag is turned on + onCloud && cloudExperiments + ? from( + cloudExperiments + .getVariation(SOLUTION_NAV_FEATURE_FLAG_NAME, false) + .catch(() => false) + ).pipe(shareReplay(1)) + : of(false); + const SpacesGridPageWithBreadcrumbs = () => { setBreadcrumbs([{ ...spacesFirstBreadcrumb, href: undefined }]); return ( @@ -87,6 +107,7 @@ export const spacesManagementApp = Object.freeze({ spacesManager={spacesManager} history={history} allowFeatureVisibility={config.allowFeatureVisibility} + isSolutionNavEnabled$={isSolutionNavEnabled$} /> ); }; @@ -113,6 +134,7 @@ export const spacesManagementApp = Object.freeze({ onLoadSpace={onLoadSpace} history={history} allowFeatureVisibility={config.allowFeatureVisibility} + isSolutionNavEnabled$={isSolutionNavEnabled$} /> ); }; diff --git a/x-pack/plugins/spaces/public/plugin.tsx b/x-pack/plugins/spaces/public/plugin.tsx index 14d816739b4c98..01e9eacaddaea5 100644 --- a/x-pack/plugins/spaces/public/plugin.tsx +++ b/x-pack/plugins/spaces/public/plugin.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import type { CloudExperimentsPluginStart } from '@kbn/cloud-experiments-plugin/common'; +import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; import type { FeaturesPluginStart } from '@kbn/features-plugin/public'; import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; @@ -23,11 +25,14 @@ import { getUiApi } from './ui_api'; export interface PluginsSetup { home?: HomePublicPluginSetup; management?: ManagementSetup; + cloud?: CloudSetup; } export interface PluginsStart { features: FeaturesPluginStart; management?: ManagementStart; + cloud?: CloudStart; + cloudExperiments?: CloudExperimentsPluginStart; } /** diff --git a/x-pack/plugins/spaces/tsconfig.json b/x-pack/plugins/spaces/tsconfig.json index b0da959cc57ea1..9f792528733078 100644 --- a/x-pack/plugins/spaces/tsconfig.json +++ b/x-pack/plugins/spaces/tsconfig.json @@ -37,6 +37,7 @@ "@kbn/utility-types-jest", "@kbn/security-plugin-types-public", "@kbn/cloud-plugin", + "@kbn/cloud-experiments-plugin", ], "exclude": [ "target/**/*", diff --git a/x-pack/test/functional/apps/spaces/create_edit_space.ts b/x-pack/test/functional/apps/spaces/create_edit_space.ts new file mode 100644 index 00000000000000..cfffc752cca0c5 --- /dev/null +++ b/x-pack/test/functional/apps/spaces/create_edit_space.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 { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'settings', 'security', 'spaceSelector']); + const testSubjects = getService('testSubjects'); + + describe('edit space', () => { + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); + + describe('solution view', () => { + it('does not show solution view panel', async () => { + await PageObjects.common.navigateToUrl('management', 'kibana/spaces/edit/default', { + shouldUseHashForSubUrl: false, + }); + + await testSubjects.existOrFail('spaces-edit-page'); + await testSubjects.existOrFail('spaces-edit-page > generalPanel'); + await testSubjects.missingOrFail('spaces-edit-page > navigationPanel'); + }); + }); + }); +} diff --git a/x-pack/test/functional/apps/spaces/index.ts b/x-pack/test/functional/apps/spaces/index.ts index c951609d6a33f1..aa034f4be012b9 100644 --- a/x-pack/test/functional/apps/spaces/index.ts +++ b/x-pack/test/functional/apps/spaces/index.ts @@ -13,5 +13,6 @@ export default function spacesApp({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./feature_controls/spaces_security')); loadTestFile(require.resolve('./spaces_selection')); loadTestFile(require.resolve('./enter_space')); + loadTestFile(require.resolve('./create_edit_space')); }); } diff --git a/x-pack/test/functional/apps/spaces/solution_view_flag_enabled/config.ts b/x-pack/test/functional/apps/spaces/solution_view_flag_enabled/config.ts new file mode 100644 index 00000000000000..0d286f5ffa621c --- /dev/null +++ b/x-pack/test/functional/apps/spaces/solution_view_flag_enabled/config.ts @@ -0,0 +1,31 @@ +/* + * 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'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + kbnTestServer: { + ...functionalConfig.get('kbnTestServer'), + serverArgs: [ + ...functionalConfig.get('kbnTestServer.serverArgs'), + '--xpack.cloud_integrations.experiments.enabled=true', + '--xpack.cloud_integrations.experiments.launch_darkly.sdk_key=a_string', + '--xpack.cloud_integrations.experiments.launch_darkly.client_id=a_string', + '--xpack.cloud_integrations.experiments.flag_overrides.solutionNavEnabled=true', + // Note: the base64 string in the cloud.id config contains the ES endpoint required in the functional tests + '--xpack.cloud.id=ftr_fake_cloud_id:aGVsbG8uY29tOjQ0MyRFUzEyM2FiYyRrYm4xMjNhYmM=', + '--xpack.cloud.base_url=https://cloud.elastic.co', + '--xpack.cloud.deployment_url=/deployments/deploymentId', + ], + }, + }; +} diff --git a/x-pack/test/functional/apps/spaces/solution_view_flag_enabled/create_edit_space.ts b/x-pack/test/functional/apps/spaces/solution_view_flag_enabled/create_edit_space.ts new file mode 100644 index 00000000000000..b6b5eff6ef5f28 --- /dev/null +++ b/x-pack/test/functional/apps/spaces/solution_view_flag_enabled/create_edit_space.ts @@ -0,0 +1,69 @@ +/* + * 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 ({ getPageObjects, getService }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'settings', 'security', 'spaceSelector']); + const testSubjects = getService('testSubjects'); + const find = getService('find'); + + describe('edit space', () => { + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); + + describe('solution view', () => { + it('does show the solution view panel', async () => { + await PageObjects.common.navigateToUrl('management', 'kibana/spaces/edit/default', { + shouldUseHashForSubUrl: false, + }); + + await testSubjects.existOrFail('spaces-edit-page'); + await testSubjects.existOrFail('spaces-edit-page > generalPanel'); + await testSubjects.existOrFail('spaces-edit-page > navigationPanel'); + }); + + it('changes the space solution and updates the side navigation', async () => { + await PageObjects.common.navigateToUrl('management', 'kibana/spaces/edit/default', { + shouldUseHashForSubUrl: false, + }); + + // Make sure we are on the classic side nav + await testSubjects.existOrFail('mgtSideBarNav'); + await testSubjects.missingOrFail('searchSideNav'); + + // change to Enterprise Search + await PageObjects.spaceSelector.changeSolutionView('es'); + await PageObjects.spaceSelector.clickSaveSpaceCreation(); + await PageObjects.spaceSelector.confirmModal(); + + await find.waitForDeletedByCssSelector('.kibanaWelcomeLogo'); + + // Search side nav is loaded + await testSubjects.existOrFail('searchSideNav'); + await testSubjects.missingOrFail('mgtSideBarNav'); + + // change back to classic + await PageObjects.common.navigateToUrl('management', 'kibana/spaces/edit/default', { + shouldUseHashForSubUrl: false, + }); + await PageObjects.spaceSelector.changeSolutionView('classic'); + await PageObjects.spaceSelector.clickSaveSpaceCreation(); + await PageObjects.spaceSelector.confirmModal(); + + await testSubjects.existOrFail('mgtSideBarNav'); + await testSubjects.missingOrFail('searchSideNav'); + }); + }); + }); +} diff --git a/x-pack/test/functional/apps/spaces/solution_view_flag_enabled/index.ts b/x-pack/test/functional/apps/spaces/solution_view_flag_enabled/index.ts new file mode 100644 index 00000000000000..99ce8f2ab16e7a --- /dev/null +++ b/x-pack/test/functional/apps/spaces/solution_view_flag_enabled/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function spacesApp({ loadTestFile }: FtrProviderContext) { + describe('Spaces app (with solution view)', function spacesAppTestSuite() { + loadTestFile(require.resolve('./create_edit_space')); + }); +} diff --git a/x-pack/test/functional/page_objects/space_selector_page.ts b/x-pack/test/functional/page_objects/space_selector_page.ts index 8c56dee81f4353..a9bea52bcd2e88 100644 --- a/x-pack/test/functional/page_objects/space_selector_page.ts +++ b/x-pack/test/functional/page_objects/space_selector_page.ts @@ -120,6 +120,22 @@ export class SpaceSelectorPageObject extends FtrService { await this.testSubjects.setValue('euiColorPickerAnchor', hexValue); } + async openSolutionViewSelect() { + const solutionViewSelect = await this.testSubjects.find('solutionViewSelect'); + const classes = await solutionViewSelect.getAttribute('class'); + + const isOpen = classes?.includes('isOpen') ?? false; + if (!isOpen) { + await solutionViewSelect.click(); + } + } + + async changeSolutionView(solution: 'es' | 'oblt' | 'security' | 'classic') { + await this.openSolutionViewSelect(); + const serialized = solution.charAt(0).toUpperCase() + solution.slice(1); + await this.testSubjects.click(`solutionView${serialized}Option`); + } + async clickShowFeatures() { await this.testSubjects.click('show-hide-section-link'); } @@ -208,6 +224,11 @@ export class SpaceSelectorPageObject extends FtrService { await this.testSubjects.click('confirmModalConfirmButton'); } + // Generic for any confirm modal + async confirmModal() { + await this.testSubjects.click('confirmModalConfirmButton'); + } + async clickOnSpaceb() { await this.testSubjects.click('space-avatar-space_b'); } From 5e346b2561d36efc6e0cd661027e2111474f6232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yulia=20=C4=8Cech?= <6585477+yuliacech@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:37:04 +0200 Subject: [PATCH 100/123] [Console] Enable monaco by default (#184862) ## Summary Closes https://github.com/elastic/kibana/issues/184025 This PR enables the migration from Ace to Monaco in Dev Tools Console by default in the main branch. All serverless projects will still have the migration disabled by default. After 8.15 is branched, the migration will be disabled there as well. The intended release version for this migration is 8.16. ### Functional tests This PR creates a copy of functional tests for Monaco Console and keeps the tests for Ace in a separate folder. When the migration is released, we can remove the code for Ace together with tests. The Monaco tests are not the exact copy of the Ace tests, since some functionality and autocomplete behaviour is slightly different in the migrated Console. For example, the auto-closing of brackets works in Monaco when typing something, but is not kicking in in the tests. Flaky test runner ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .buildkite/ftr_configs.yml | 3 +- config/serverless.yml | 2 + packages/kbn-monaco/src/console/types.ts | 2 +- .../__snapshots__/code_editor.test.tsx.snap | 1 + .../code_editor/impl/code_editor.tsx | 6 +- .../editor/monaco/monaco_editor.tsx | 2 + .../editor/monaco/monaco_editor_output.tsx | 1 + .../editor/monaco/utils/requests_utils.ts | 4 +- .../editor/monaco/utils/tokens_utils.ts | 2 +- src/plugins/console/server/config.ts | 2 +- .../apps/console/{ => ace}/_autocomplete.ts | 2 +- .../apps/console/{ => ace}/_comments.ts | 2 +- .../apps/console/{ => ace}/_console.ts | 31 +- .../apps/console/{ => ace}/_console_ccs.ts | 2 +- .../apps/console/{ => ace}/_context_menu.ts | 2 +- .../{ => ace}/_misc_console_behavior.ts | 2 +- .../apps/console/{ => ace}/_settings.ts | 2 +- .../apps/console/{ => ace}/_text_input.ts | 2 +- .../apps/console/{ => ace}/_variables.ts | 2 +- .../apps/console/{ => ace}/_vector_tile.ts | 2 +- .../apps/console/{ => ace}/_xjson.ts | 2 +- test/functional/apps/console/ace/config.ts | 27 ++ .../apps/console/{index.js => ace/index.ts} | 4 +- .../apps/console/monaco/_autocomplete.ts | 374 ++++++++++++++++++ .../apps/console/monaco/_comments.ts | 149 +++++++ .../apps/console/monaco/_console.ts | 150 +++++++ .../apps/console/monaco/_console_ccs.ts | 54 +++ .../apps/console/monaco/_context_menu.ts | 104 +++++ .../console/monaco/_misc_console_behavior.ts | 129 ++++++ .../apps/console/monaco/_settings.ts | 41 ++ .../apps/console/monaco/_text_input.ts | 101 +++++ .../apps/console/monaco/_variables.ts | 71 ++++ .../apps/console/monaco/_vector_tile.ts | 51 +++ test/functional/apps/console/monaco/_xjson.ts | 118 ++++++ .../apps/console/{ => monaco}/config.ts | 4 +- test/functional/apps/console/monaco/index.ts | 34 ++ .../controls/common/config.ts | 8 + .../controls/options_list/config.ts | 8 + test/functional/config.ccs.ts | 2 +- test/functional/firefox/console.config.ts | 2 +- test/functional/page_objects/console_page.ts | 160 ++++++++ test/tsconfig.json | 1 + .../apps/reporting_management/config.ts | 8 + 43 files changed, 1626 insertions(+), 50 deletions(-) rename test/functional/apps/console/{ => ace}/_autocomplete.ts (99%) rename test/functional/apps/console/{ => ace}/_comments.ts (98%) rename test/functional/apps/console/{ => ace}/_console.ts (90%) rename test/functional/apps/console/{ => ace}/_console_ccs.ts (96%) rename test/functional/apps/console/{ => ace}/_context_menu.ts (98%) rename test/functional/apps/console/{ => ace}/_misc_console_behavior.ts (98%) rename test/functional/apps/console/{ => ace}/_settings.ts (95%) rename test/functional/apps/console/{ => ace}/_text_input.ts (98%) rename test/functional/apps/console/{ => ace}/_variables.ts (97%) rename test/functional/apps/console/{ => ace}/_vector_tile.ts (96%) rename test/functional/apps/console/{ => ace}/_xjson.ts (99%) create mode 100644 test/functional/apps/console/ace/config.ts rename test/functional/apps/console/{index.js => ace/index.ts} (89%) create mode 100644 test/functional/apps/console/monaco/_autocomplete.ts create mode 100644 test/functional/apps/console/monaco/_comments.ts create mode 100644 test/functional/apps/console/monaco/_console.ts create mode 100644 test/functional/apps/console/monaco/_console_ccs.ts create mode 100644 test/functional/apps/console/monaco/_context_menu.ts create mode 100644 test/functional/apps/console/monaco/_misc_console_behavior.ts create mode 100644 test/functional/apps/console/monaco/_settings.ts create mode 100644 test/functional/apps/console/monaco/_text_input.ts create mode 100644 test/functional/apps/console/monaco/_variables.ts create mode 100644 test/functional/apps/console/monaco/_vector_tile.ts create mode 100644 test/functional/apps/console/monaco/_xjson.ts rename test/functional/apps/console/{ => monaco}/config.ts (87%) create mode 100644 test/functional/apps/console/monaco/index.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index c12bcf333dc08a..55f23715e3468f 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -98,7 +98,8 @@ enabled: - test/api_integration/config.js - test/examples/config.js - test/functional/apps/bundles/config.ts - - test/functional/apps/console/config.ts + - test/functional/apps/console/monaco/config.ts + - test/functional/apps/console/ace/config.ts - test/functional/apps/context/config.ts - test/functional/apps/dashboard_elements/controls/common/config.ts - test/functional/apps/dashboard_elements/controls/options_list/config.ts diff --git a/config/serverless.yml b/config/serverless.yml index 6658eba7095c16..bea8e422e2925e 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -108,6 +108,8 @@ xpack.index_management.enableDataStreamsStorageColumn: false xpack.index_management.enableMappingsSourceFieldSection: false # Disable toggle for enabling data retention in DSL form from Index Management UI xpack.index_management.enableTogglingDataRetention: false +# Disable the Monaco migration in Console +console.dev.enableMonaco: false # Keep deeplinks visible so that they are shown in the sidenav dev_tools.deeplinks.navLinkStatus: visible diff --git a/packages/kbn-monaco/src/console/types.ts b/packages/kbn-monaco/src/console/types.ts index 986ffd67045088..346bd0e6beeebd 100644 --- a/packages/kbn-monaco/src/console/types.ts +++ b/packages/kbn-monaco/src/console/types.ts @@ -15,7 +15,7 @@ export interface ParsedRequest { startOffset: number; endOffset?: number; method: string; - url: string; + url?: string; data?: Array>; } export interface ConsoleParserResult { diff --git a/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap b/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap index a538b4845231a9..e0fe7d3ea23863 100644 --- a/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap +++ b/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap @@ -169,6 +169,7 @@ exports[` is rendered 1`] = `

} + data-test-subj="codeEditorAccessibilityOverlay" delay="regular" display="block" position="top" diff --git a/packages/shared-ux/code_editor/impl/code_editor.tsx b/packages/shared-ux/code_editor/impl/code_editor.tsx index 2e8d2c2732ff73..35dcb275b52f9d 100644 --- a/packages/shared-ux/code_editor/impl/code_editor.tsx +++ b/packages/shared-ux/code_editor/impl/code_editor.tsx @@ -155,6 +155,8 @@ export interface CodeEditorProps { * Enables the editor to get disabled when pressing ESC to resolve focus trapping for accessibility. */ accessibilityOverlayEnabled?: boolean; + + dataTestSubj?: string; } export const CodeEditor: React.FC = ({ @@ -186,6 +188,7 @@ export const CodeEditor: React.FC = ({ }), fitToContent, accessibilityOverlayEnabled = true, + dataTestSubj, }) => { const { colorMode, euiTheme } = useEuiTheme(); const useDarkTheme = useDarkThemeProp ?? colorMode === 'DARK'; @@ -280,6 +283,7 @@ export const CodeEditor: React.FC = ({ return ( @@ -485,7 +489,7 @@ export const CodeEditor: React.FC = ({
{accessibilityOverlayEnabled && renderPrompt()} diff --git a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor.tsx b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor.tsx index bc9d6cf2ee3c97..02f978f7919a59 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor.tsx +++ b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor.tsx @@ -115,6 +115,7 @@ export const MonacoEditor = ({ initialTextValue }: EditorProps) => { width: 100%; `} ref={divRef} + data-test-subj="consoleMonacoEditorContainer" > { { { - const url = removeTrailingWhitespaces(parsedRequest.url); - const method = parsedRequest.method.toUpperCase(); + const url = parsedRequest.url ? removeTrailingWhitespaces(parsedRequest.url) : ''; + const method = parsedRequest.method?.toUpperCase() ?? ''; const data = parsedRequest.data?.map((parsedData) => JSON.stringify(parsedData, null, 2)); return { url, method, data: data ?? [] }; }; diff --git a/src/plugins/console/public/application/containers/editor/monaco/utils/tokens_utils.ts b/src/plugins/console/public/application/containers/editor/monaco/utils/tokens_utils.ts index f52a0bb6a9079e..decbe0d4fdd9ab 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/utils/tokens_utils.ts +++ b/src/plugins/console/public/application/containers/editor/monaco/utils/tokens_utils.ts @@ -25,7 +25,7 @@ export const parseLine = (line: string): ParsedLineTokens => { // try to parse into method and url (split on whitespace) const parts = line.split(whitespacesRegex); // 1st part is the method - const method = parts[0]; + const method = parts[0].toUpperCase(); // 2nd part is the url const url = parts[1]; // try to parse into url path and url params (split on question mark) diff --git a/src/plugins/console/server/config.ts b/src/plugins/console/server/config.ts index e5a54042f50036..953cc1f84ea606 100644 --- a/src/plugins/console/server/config.ts +++ b/src/plugins/console/server/config.ts @@ -31,7 +31,7 @@ const schemaLatest = schema.object( defaultValue: 'stack', }), }), - dev: schema.object({ enableMonaco: schema.boolean({ defaultValue: false }) }), + dev: schema.object({ enableMonaco: schema.boolean({ defaultValue: true }) }), }, { defaultValue: undefined } ); diff --git a/test/functional/apps/console/_autocomplete.ts b/test/functional/apps/console/ace/_autocomplete.ts similarity index 99% rename from test/functional/apps/console/_autocomplete.ts rename to test/functional/apps/console/ace/_autocomplete.ts index 2f9d8db9cf9d20..fe329e8d2c320f 100644 --- a/test/functional/apps/console/_autocomplete.ts +++ b/test/functional/apps/console/ace/_autocomplete.ts @@ -9,7 +9,7 @@ import _ from 'lodash'; import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); diff --git a/test/functional/apps/console/_comments.ts b/test/functional/apps/console/ace/_comments.ts similarity index 98% rename from test/functional/apps/console/_comments.ts rename to test/functional/apps/console/ace/_comments.ts index de8bcda60786ba..8ef708d68b44f6 100644 --- a/test/functional/apps/console/_comments.ts +++ b/test/functional/apps/console/ace/_comments.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); diff --git a/test/functional/apps/console/_console.ts b/test/functional/apps/console/ace/_console.ts similarity index 90% rename from test/functional/apps/console/_console.ts rename to test/functional/apps/console/ace/_console.ts index cc3b8dbc7073d5..19de1d941fdaed 100644 --- a/test/functional/apps/console/_console.ts +++ b/test/functional/apps/console/ace/_console.ts @@ -8,33 +8,8 @@ import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -const DEFAULT_REQUEST = ` -# Welcome to the Dev Tools Console! -# -# You can use Console to explore the Elasticsearch API. See the \n Elasticsearch API reference to learn more: -# https://www.elastic.co/guide/en/elasticsearch/reference/current\n /rest-apis.html -# -# Here are a few examples to get you started. - - -# Create an index -PUT /my-index - - -# Add a document to my-index -POST /my-index/_doc -{ - "id": "park_rocky-mountain", - "title": "Rocky Mountain", - "description": "Bisected north to south by the Continental \n Divide, this portion of the Rockies has ecosystems varying \n from over 150 riparian lakes to montane and subalpine forests \n to treeless alpine tundra." -} - - -# Perform a search in my-index -GET /my-index/_search?q="rocky mountain" -`.trim(); +import { DEFAULT_INPUT_VALUE } from '@kbn/console-plugin/common/constants'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); @@ -58,7 +33,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async () => { const actualRequest = await PageObjects.console.getRequest(); log.debug(actualRequest); - expect(actualRequest.trim()).to.eql(DEFAULT_REQUEST); + expect(actualRequest.replace(/\s/g, '')).to.eql(DEFAULT_INPUT_VALUE.replace(/\s/g, '')); }); }); diff --git a/test/functional/apps/console/_console_ccs.ts b/test/functional/apps/console/ace/_console_ccs.ts similarity index 96% rename from test/functional/apps/console/_console_ccs.ts rename to test/functional/apps/console/ace/_console_ccs.ts index 8778c2e6e70bb1..57ab547af4e497 100644 --- a/test/functional/apps/console/_console_ccs.ts +++ b/test/functional/apps/console/ace/_console_ccs.ts @@ -7,7 +7,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); diff --git a/test/functional/apps/console/_context_menu.ts b/test/functional/apps/console/ace/_context_menu.ts similarity index 98% rename from test/functional/apps/console/_context_menu.ts rename to test/functional/apps/console/ace/_context_menu.ts index 4051804d7407f7..677aa1c43fe392 100644 --- a/test/functional/apps/console/_context_menu.ts +++ b/test/functional/apps/console/ace/_context_menu.ts @@ -7,7 +7,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); diff --git a/test/functional/apps/console/_misc_console_behavior.ts b/test/functional/apps/console/ace/_misc_console_behavior.ts similarity index 98% rename from test/functional/apps/console/_misc_console_behavior.ts rename to test/functional/apps/console/ace/_misc_console_behavior.ts index 2920813f2cca08..303004ad424466 100644 --- a/test/functional/apps/console/_misc_console_behavior.ts +++ b/test/functional/apps/console/ace/_misc_console_behavior.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); diff --git a/test/functional/apps/console/_settings.ts b/test/functional/apps/console/ace/_settings.ts similarity index 95% rename from test/functional/apps/console/_settings.ts rename to test/functional/apps/console/ace/_settings.ts index a2802db67e8591..f42a078ff48e7b 100644 --- a/test/functional/apps/console/_settings.ts +++ b/test/functional/apps/console/ace/_settings.ts @@ -7,7 +7,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); diff --git a/test/functional/apps/console/_text_input.ts b/test/functional/apps/console/ace/_text_input.ts similarity index 98% rename from test/functional/apps/console/_text_input.ts rename to test/functional/apps/console/ace/_text_input.ts index 8826b24931c07b..b60a3b8df8f79d 100644 --- a/test/functional/apps/console/_text_input.ts +++ b/test/functional/apps/console/ace/_text_input.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); diff --git a/test/functional/apps/console/_variables.ts b/test/functional/apps/console/ace/_variables.ts similarity index 97% rename from test/functional/apps/console/_variables.ts rename to test/functional/apps/console/ace/_variables.ts index 8e09460b4dc6cc..91474de06d678d 100644 --- a/test/functional/apps/console/_variables.ts +++ b/test/functional/apps/console/ace/_variables.ts @@ -7,7 +7,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ getService, getPageObjects }: FtrProviderContext) => { const retry = getService('retry'); diff --git a/test/functional/apps/console/_vector_tile.ts b/test/functional/apps/console/ace/_vector_tile.ts similarity index 96% rename from test/functional/apps/console/_vector_tile.ts rename to test/functional/apps/console/ace/_vector_tile.ts index 77b186227ed288..376bf5ccb7eefe 100644 --- a/test/functional/apps/console/_vector_tile.ts +++ b/test/functional/apps/console/ace/_vector_tile.ts @@ -7,7 +7,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'console', 'header', 'home']); diff --git a/test/functional/apps/console/_xjson.ts b/test/functional/apps/console/ace/_xjson.ts similarity index 99% rename from test/functional/apps/console/_xjson.ts rename to test/functional/apps/console/ace/_xjson.ts index 6a4f352a3ad013..ae9bfb519ba674 100644 --- a/test/functional/apps/console/_xjson.ts +++ b/test/functional/apps/console/ace/_xjson.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { rgbToHex } from '@elastic/eui'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ getService, getPageObjects }: FtrProviderContext) => { const retry = getService('retry'); diff --git a/test/functional/apps/console/ace/config.ts b/test/functional/apps/console/ace/config.ts new file mode 100644 index 00000000000000..013c5b26d0cdb6 --- /dev/null +++ b/test/functional/apps/console/ace/config.ts @@ -0,0 +1,27 @@ +/* + * 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 { FtrConfigProviderContext } from '@kbn/test'; +import { configureHTTP2 } from '../../../../common/configure_http2'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return configureHTTP2({ + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + kbnTestServer: { + ...functionalConfig.get('kbnTestServer'), + serverArgs: [ + ...functionalConfig.get('kbnTestServer.serverArgs'), + // disabling the monaco editor to run tests for ace + `--console.dev.enableMonaco=false`, + ], + }, + }); +} diff --git a/test/functional/apps/console/index.js b/test/functional/apps/console/ace/index.ts similarity index 89% rename from test/functional/apps/console/index.js rename to test/functional/apps/console/ace/index.ts index 36fb3f5421540d..7274118daaafe9 100644 --- a/test/functional/apps/console/index.js +++ b/test/functional/apps/console/ace/index.ts @@ -6,7 +6,9 @@ * Side Public License, v 1. */ -export default function ({ getService, loadTestFile }) { +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { const browser = getService('browser'); const config = getService('config'); diff --git a/test/functional/apps/console/monaco/_autocomplete.ts b/test/functional/apps/console/monaco/_autocomplete.ts new file mode 100644 index 00000000000000..e6ed83ad263382 --- /dev/null +++ b/test/functional/apps/console/monaco/_autocomplete.ts @@ -0,0 +1,374 @@ +/* + * 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 _ from 'lodash'; +import expect from '@kbn/expect'; +import { asyncForEach } from '@kbn/std'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const log = getService('log'); + const retry = getService('retry'); + const PageObjects = getPageObjects(['common', 'console', 'header']); + const find = getService('find'); + + describe('console autocomplete feature', function describeIndexTests() { + this.tags('includeFirefox'); + before(async () => { + log.debug('navigateTo console'); + await PageObjects.common.navigateToApp('console'); + // Ensure that the text area can be interacted with + await PageObjects.console.closeHelpIfExists(); + await PageObjects.console.monaco.clearEditorText(); + log.debug('setAutocompleteTrace true'); + await PageObjects.console.setAutocompleteTrace(true); + }); + + after(async () => { + log.debug('setAutocompleteTrace false'); + await PageObjects.console.setAutocompleteTrace(false); + }); + + it('should provide basic auto-complete functionality', async () => { + await PageObjects.console.monaco.enterText(`GET _search\n`); + await PageObjects.console.monaco.pressEnter(); + await PageObjects.console.monaco.enterText(`{\n\t"query": {`); + await PageObjects.console.monaco.pressEnter(); + await PageObjects.console.sleepForDebouncePeriod(); + await PageObjects.console.monaco.promptAutocomplete(); + expect(PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(true); + }); + + describe('Autocomplete behavior', () => { + beforeEach(async () => { + await PageObjects.console.monaco.clearEditorText(); + }); + + it('HTTP methods', async () => { + const suggestions = { + G: ['GET'], + P: ['PATCH', 'POST', 'PUT'], + D: ['DELETE'], + H: ['HEAD'], + }; + for (const [char, methods] of Object.entries(suggestions)) { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.monaco.enterText(char); + + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.monaco.isAutocompleteVisible() + ); + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(true); + + for (const [i, method] of methods.entries()) { + expect(await PageObjects.console.monaco.getAutocompleteSuggestion(i)).to.be.eql(method); + } + + await PageObjects.console.monaco.pressEscape(); + await PageObjects.console.monaco.clearEditorText(); + } + }); + + it('ES API endpoints', async () => { + const suggestions = { + 'GET _': ['_alias', '_all'], + 'PUT _': ['_all'], + 'POST _': ['_aliases', '_all'], + 'DELETE _': ['_all'], + 'HEAD _': ['_alias', '_all'], + }; + for (const [text, endpoints] of Object.entries(suggestions)) { + for (const char of text) { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.monaco.enterText(char); + } + + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.monaco.isAutocompleteVisible() + ); + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(true); + + for (const [i, endpoint] of endpoints.entries()) { + expect(await PageObjects.console.monaco.getAutocompleteSuggestion(i)).to.be.eql( + endpoint + ); + } + + await PageObjects.console.monaco.pressEscape(); + await PageObjects.console.monaco.pressEnter(); + } + }); + + it('JSON autocompletion with placeholder fields', async () => { + await PageObjects.console.monaco.enterText('GET _search\n'); + await PageObjects.console.monaco.enterText('{'); + await PageObjects.console.monaco.pressEnter(); + + for (const char of '"ag') { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.monaco.enterText(char); + } + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.monaco.isAutocompleteVisible() + ); + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(true); + await PageObjects.console.monaco.pressEnter(); + await PageObjects.console.sleepForDebouncePeriod(); + + expect((await PageObjects.console.monaco.getEditorText()).replace(/\s/g, '')).to.be.eql( + ` +GET _search +{ + "aggs": { + "NAME": { + "AGG_TYPE": {} + } + } +} +`.replace(/\s/g, '') + ); + }); + + it('Dynamic autocomplete', async () => { + await PageObjects.console.monaco.enterText('POST test/_doc\n{}'); + await PageObjects.console.clickPlay(); + + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await PageObjects.console.getResponseStatus()).to.be('201'); + + await PageObjects.console.monaco.pressEnter(); + for (const char of 'POST t') { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.monaco.enterText(char); + } + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.monaco.isAutocompleteVisible() + ); + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(true); + + expect(await PageObjects.console.monaco.getAutocompleteSuggestion(0)).to.be.eql('test'); + }); + }); + + describe('anti-regression watchdogs', () => { + beforeEach(async () => { + await PageObjects.console.monaco.clearEditorText(); + }); + + // flaky + it.skip('should suppress auto-complete on arrow keys', async () => { + await PageObjects.console.monaco.enterText(`\nGET _search\nGET _search`); + await PageObjects.console.monaco.pressEnter(); + const keyPresses = [ + 'pressUp', + 'pressUp', + 'pressDown', + 'pressDown', + 'pressRight', + 'pressRight', + 'pressLeft', + 'pressLeft', + ] as const; + for (const keyPress of keyPresses) { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key', keyPress); + await PageObjects.console.monaco[keyPress](); + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(false); + } + }); + + it('should activate auto-complete for methods case-insensitively', async () => { + const methods = _.sampleSize( + _.compact( + ` + GET GEt GeT Get gET gEt geT get + PUT PUt PuT Put pUT pUt puT put + POST POSt POsT POst PoST PoSt PosT Post pOST pOSt pOsT pOst poST poSt posT post + DELETE DELETe DELEtE DELEte DELeTE DELeTe DELetE DELete DElETE DElETe DElEtE DElEte DEleTE DEleTe DEletE DElete + DeLETE DeLETe DeLEtE DeLEte DeLeTE DeLeTe DeLetE DeLete DelETE DelETe DelEtE DelEte DeleTE DeleTe DeletE Delete + dELETE dELETe dELEtE dELEte dELeTE dELeTe dELetE dELete dElETE dElETe dElEtE dElEte dEleTE dEleTe dEletE dElete + deLETE deLETe deLEtE deLEte deLeTE deLeTe deLetE deLete delETE delETe delEtE delEte deleTE deleTe deletE delete + HEAD HEAd HEaD HEad HeAD HeAd HeaD Head hEAD hEAd hEaD hEad heAD heAd heaD head + `.split(/\s+/m) + ), + 20 // 20 of 112 (approx. one-fifth) should be enough for testing + ); + + for (const method of methods) { + await PageObjects.console.monaco.clearEditorText(); + + for (const char of method.slice(0, -1)) { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.monaco.enterText(char); // e.g. 'P' -> 'Po' -> 'Pos' + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.monaco.isAutocompleteVisible() + ); + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(true); + } + + for (const char of [method.at(-1), ' ', '_']) { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.monaco.enterText(char!); // e.g. 'Post ' -> 'Post _' + } + + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.monaco.isAutocompleteVisible() + ); + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(true); + } + }); + + it('should activate auto-complete for a single character immediately following a slash in URL', async () => { + await PageObjects.console.monaco.enterText('GET .kibana'); + + for (const char of ['/', '_']) { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.monaco.enterText(char); // i.e. 'GET .kibana/' -> 'GET .kibana/_' + } + + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.monaco.isAutocompleteVisible() + ); + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(true); + }); + + it('should activate auto-complete for multiple indices after comma in URL', async () => { + await PageObjects.console.monaco.enterText('GET _cat/indices/.kibana'); + + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type ","'); + await PageObjects.console.monaco.enterText(','); // i.e. 'GET /_cat/indices/.kibana,' + + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type Ctrl+SPACE'); + await PageObjects.console.monaco.pressCtrlSpace(); + + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.monaco.isAutocompleteVisible() + ); + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(true); + }); + + // not fixed for monaco yet https://github.com/elastic/kibana/issues/184442 + it.skip('should not activate auto-complete after comma following endpoint in URL', async () => { + await PageObjects.console.monaco.enterText('GET _search'); + + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type ","'); + await PageObjects.console.monaco.enterText(','); // i.e. 'GET _search,' + + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type Ctrl+SPACE'); + await PageObjects.console.monaco.pressCtrlSpace(); + + expect(await PageObjects.console.monaco.isAutocompleteVisible()).to.be.eql(false); + }); + }); + + // not implemented for monaco yet https://github.com/elastic/kibana/issues/184856 + describe.skip('with a missing comma in query', () => { + const LINE_NUMBER = 4; + beforeEach(async () => { + await PageObjects.console.clearTextArea(); + await PageObjects.console.enterRequest(); + await PageObjects.console.pressEnter(); + }); + + it('should add a comma after previous non empty line', async () => { + await PageObjects.console.enterText(`{\n\t"query": {\n\t\t"match": {}`); + await PageObjects.console.pressEnter(); + await PageObjects.console.pressEnter(); + await PageObjects.console.pressEnter(); + await PageObjects.console.sleepForDebouncePeriod(); + await PageObjects.console.promptAutocomplete(); + await PageObjects.console.pressEnter(); + await retry.try(async () => { + let conApp = await find.byCssSelector('.conApp'); + const firstInnerHtml = await conApp.getAttribute('innerHTML'); + await PageObjects.common.sleep(500); + conApp = await find.byCssSelector('.conApp'); + const secondInnerHtml = await conApp.getAttribute('innerHTML'); + return firstInnerHtml === secondInnerHtml; + }); + const textAreaString = await PageObjects.console.getAllVisibleText(); + log.debug('Text Area String Value==================\n'); + log.debug(textAreaString); + expect(textAreaString).to.contain(','); + const text = await PageObjects.console.getVisibleTextAt(LINE_NUMBER); + const lastChar = text.charAt(text.length - 1); + expect(lastChar).to.be.eql(','); + }); + + it('should add a comma after the triple quoted strings', async () => { + await PageObjects.console.enterText(`{\n\t"query": {\n\t\t"term": """some data"""`); + await PageObjects.console.pressEnter(); + await PageObjects.console.sleepForDebouncePeriod(); + await PageObjects.console.promptAutocomplete(); + await PageObjects.console.pressEnter(); + + await retry.waitForWithTimeout('text area to contain comma', 25000, async () => { + const textAreaString = await PageObjects.console.getAllVisibleText(); + return textAreaString.includes(','); + }); + + const text = await PageObjects.console.getVisibleTextAt(LINE_NUMBER); + const lastChar = text.charAt(text.length - 1); + expect(lastChar).to.be.eql(','); + }); + }); + + describe('with conditional templates', async () => { + const CONDITIONAL_TEMPLATES = [ + { + type: 'fs', + template: `"location": "path"`, + }, + { + type: 'url', + template: `"url": ""`, + }, + { type: 's3', template: `"bucket": ""` }, + { + type: 'azure', + template: `"path": ""`, + }, + ]; + + beforeEach(async () => { + await PageObjects.console.monaco.clearEditorText(); + await PageObjects.console.monaco.enterText('POST _snapshot/test_repo\n'); + }); + + await asyncForEach(CONDITIONAL_TEMPLATES, async ({ type, template }) => { + it('should insert different templates depending on the value of type', async () => { + await PageObjects.console.monaco.enterText(`{\n\t"type": "${type}",\n`); + await PageObjects.console.sleepForDebouncePeriod(); + // Prompt autocomplete for 'settings' + await PageObjects.console.monaco.promptAutocomplete('s'); + + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.monaco.isAutocompleteVisible() + ); + await PageObjects.console.monaco.pressEnter(); + await retry.try(async () => { + const request = await PageObjects.console.monaco.getEditorText(); + log.debug(request); + expect(request).to.contain(`${template}`); + }); + }); + }); + }); + }); +} diff --git a/test/functional/apps/console/monaco/_comments.ts b/test/functional/apps/console/monaco/_comments.ts new file mode 100644 index 00000000000000..ba8d8b6f04f074 --- /dev/null +++ b/test/functional/apps/console/monaco/_comments.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 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 expect from '@kbn/expect'; +import { asyncForEach } from '@kbn/std'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const log = getService('log'); + const PageObjects = getPageObjects(['common', 'console', 'header']); + + // flaky + describe.skip('console app', function testComments() { + this.tags('includeFirefox'); + before(async () => { + log.debug('navigateTo console'); + await PageObjects.common.navigateToApp('console'); + await PageObjects.console.closeHelpIfExists(); + }); + + describe('with comments', async () => { + const enterRequest = async (url: string, body: string) => { + await PageObjects.console.monaco.clearEditorText(); + await PageObjects.console.monaco.enterText(`${url}\n${body}`); + }; + + async function runTests( + tests: Array<{ description: string; url?: string; body: string }>, + fn: () => Promise + ) { + await asyncForEach(tests, async ({ description, url, body }) => { + it(description, async () => { + await enterRequest(url ?? '\nGET search', body); + await fn(); + }); + }); + } + + describe('with single line comments', async () => { + await runTests( + [ + { + url: '\n// GET _search', + body: '', + description: 'should allow in request url, using //', + }, + { + body: '{\n\t\t"query": {\n\t\t\t// "match_all": {}\n}\n}', + description: 'should allow in request body, using //', + }, + { + url: '\n # GET _search', + body: '', + description: 'should allow in request url, using #', + }, + { + body: '{\n\t\t"query": {\n\t\t\t# "match_all": {}\n}\n}', + description: 'should allow in request body, using #', + }, + { + description: 'should accept as field names, using //', + body: '{\n "//": {} }', + }, + { + description: 'should accept as field values, using //', + body: '{\n "f": "//" }', + }, + { + description: 'should accept as field names, using #', + body: '{\n "#": {} }', + }, + { + description: 'should accept as field values, using #', + body: '{\n "f": "#" }', + }, + ], + async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(false); + } + ); + }); + + describe('with multiline comments', async () => { + await runTests( + [ + { + url: '\n /* \nGET _search \n*/', + body: '', + description: 'should allow in request url, using /* */', + }, + { + body: '{\n\t\t"query": {\n\t\t\t/* "match_all": {} */ \n}\n}', + description: 'should allow in request body, using /* */', + }, + { + description: 'should accept as field names, using /*', + body: '{\n "/*": {} \n\t\t /* "f": 1 */ \n}', + }, + { + description: 'should accept as field values, using */', + body: '{\n /* "f": 1 */ \n"f": "*/" \n}', + }, + ], + async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(false); + } + ); + }); + + describe('with invalid syntax in request body', async () => { + await runTests( + [ + { + description: 'should highlight invalid syntax', + body: '{\n "query": \'\'', // E.g. using single quotes + }, + ], + + async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(true); + } + ); + }); + + describe('with invalid request', async () => { + await runTests( + [ + { + description: 'with invalid character should display error marker', + body: '{\n $ "query": {}', + }, + { + description: 'with missing field name', + body: '{\n "query": {},\n {}', + }, + ], + async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(true); + } + ); + }); + }); + }); +} diff --git a/test/functional/apps/console/monaco/_console.ts b/test/functional/apps/console/monaco/_console.ts new file mode 100644 index 00000000000000..36bb893d5b90ff --- /dev/null +++ b/test/functional/apps/console/monaco/_console.ts @@ -0,0 +1,150 @@ +/* + * 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 expect from '@kbn/expect'; +import { asyncForEach } from '@kbn/std'; +import { DEFAULT_INPUT_VALUE } from '@kbn/console-plugin/common/constants'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const retry = getService('retry'); + const log = getService('log'); + const browser = getService('browser'); + const PageObjects = getPageObjects(['common', 'console', 'header']); + const security = getService('security'); + + describe('console app', function describeIndexTests() { + this.tags('includeFirefox'); + before(async () => { + log.debug('navigateTo console'); + await PageObjects.common.navigateToApp('console'); + }); + beforeEach(async () => { + await PageObjects.console.closeHelpIfExists(); + }); + + it('should show the default request', async () => { + await retry.try(async () => { + const actualRequest = await PageObjects.console.monaco.getEditorText(); + log.debug(actualRequest); + expect(actualRequest.replace(/\s/g, '')).to.eql(DEFAULT_INPUT_VALUE.replace(/\s/g, '')); + }); + }); + + // issue with the url params with whitespaces https://github.com/elastic/kibana/issues/184927 + it.skip('default request response should include `"timed_out" : false`', async () => { + const expectedResponseContains = `"timed_out": false`; + await PageObjects.console.monaco.selectAllRequests(); + await PageObjects.console.clickPlay(); + await retry.try(async () => { + const actualResponse = await PageObjects.console.monaco.getOutputText(); + log.debug(actualResponse); + expect(actualResponse).to.contain(expectedResponseContains); + }); + }); + + // the resizer doesn't work the same as in ace https://github.com/elastic/kibana/issues/184352 + it.skip('should resize the editor', async () => { + const editor = await PageObjects.console.monaco.getEditor(); + await browser.setWindowSize(1300, 1100); + const initialSize = await editor.getSize(); + await browser.setWindowSize(1000, 1100); + const afterSize = await editor.getSize(); + expect(initialSize.width).to.be.greaterThan(afterSize.width); + }); + + it('should return statusCode 400 to unsupported HTTP verbs', async () => { + const expectedResponseContains = '"statusCode": 400'; + await PageObjects.console.monaco.clearEditorText(); + await PageObjects.console.monaco.enterText('OPTIONS /'); + await PageObjects.console.clickPlay(); + await retry.try(async () => { + const actualResponse = await PageObjects.console.monaco.getOutputText(); + log.debug(actualResponse); + expect(actualResponse).to.contain(expectedResponseContains); + + expect(await PageObjects.console.hasSuccessBadge()).to.be(false); + }); + }); + + describe('with kbn: prefix in request', () => { + before(async () => { + await PageObjects.console.monaco.clearEditorText(); + }); + it('it should send successful request to Kibana API', async () => { + const expectedResponseContains = 'default space'; + await PageObjects.console.monaco.enterText('GET kbn:/api/spaces/space'); + await PageObjects.console.clickPlay(); + await retry.try(async () => { + const actualResponse = await PageObjects.console.monaco.getOutputText(); + log.debug(actualResponse); + expect(actualResponse).to.contain(expectedResponseContains); + }); + }); + }); + + describe('with query params', () => { + it('should issue a successful request', async () => { + await PageObjects.console.monaco.clearEditorText(); + await PageObjects.console.monaco.enterText( + 'GET _cat/aliases?format=json&v=true&pretty=true' + ); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // set the width of the browser, so that the response status is visible + await browser.setWindowSize(1300, 1100); + await retry.try(async () => { + const status = await PageObjects.console.getResponseStatus(); + expect(status).to.eql(200); + }); + }); + }); + + describe('multiple requests output', function () { + const sendMultipleRequests = async (requests: string[]) => { + await asyncForEach(requests, async (request) => { + await PageObjects.console.monaco.enterText(request); + }); + await PageObjects.console.monaco.selectAllRequests(); + await PageObjects.console.clickPlay(); + }; + + before(async () => { + await security.testUser.setRoles(['kibana_admin', 'test_index']); + }); + + after(async () => { + await security.testUser.restoreDefaults(); + }); + + beforeEach(async () => { + await PageObjects.console.closeHelpIfExists(); + await PageObjects.console.monaco.clearEditorText(); + }); + + it('should contain comments starting with # symbol', async () => { + await sendMultipleRequests(['\n PUT test-index', '\n DELETE test-index']); + await retry.try(async () => { + const response = await PageObjects.console.monaco.getOutputText(); + log.debug(response); + expect(response).to.contain('# PUT test-index 200'); + expect(response).to.contain('# DELETE test-index 200'); + }); + }); + + // not implemented for monaco yet https://github.com/elastic/kibana/issues/184010 + it.skip('should display status badges', async () => { + await sendMultipleRequests(['\n GET _search/test', '\n GET _search']); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await PageObjects.console.hasWarningBadge()).to.be(true); + expect(await PageObjects.console.hasSuccessBadge()).to.be(true); + }); + }); + }); +} diff --git a/test/functional/apps/console/monaco/_console_ccs.ts b/test/functional/apps/console/monaco/_console_ccs.ts new file mode 100644 index 00000000000000..410518a6bfc819 --- /dev/null +++ b/test/functional/apps/console/monaco/_console_ccs.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const retry = getService('retry'); + const log = getService('log'); + const browser = getService('browser'); + const PageObjects = getPageObjects(['common', 'console']); + const remoteEsArchiver = getService('remoteEsArchiver' as 'esArchiver'); + + describe('Console App CCS', function describeIndexTests() { + this.tags('includeFirefox'); + before(async () => { + await remoteEsArchiver.loadIfNeeded( + 'test/functional/fixtures/es_archiver/logstash_functional' + ); + // resize the editor to allow the whole of the response to be displayed + await browser.setWindowSize(1200, 1800); + log.debug('navigateTo console'); + await PageObjects.common.navigateToApp('console'); + await retry.try(async () => { + await PageObjects.console.collapseHelp(); + }); + }); + + after(async () => { + await remoteEsArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + describe('Perform CCS Search in Console', () => { + before(async () => { + await PageObjects.console.monaco.clearEditorText(); + }); + it('it should be able to access remote data', async () => { + await PageObjects.console.monaco.enterText( + '\nGET ftr-remote:logstash-*/_search\n {\n "query": {\n "bool": {\n "must": [\n {"match": {"extension" : "jpg"} \n}\n]\n}\n}\n}' + ); + await PageObjects.console.clickPlay(); + await retry.try(async () => { + const actualResponse = await PageObjects.console.monaco.getOutputText(); + expect(actualResponse).to.contain('"_index": "ftr-remote:logstash-2015.09.20"'); + }); + }); + }); + }); +} diff --git a/test/functional/apps/console/monaco/_context_menu.ts b/test/functional/apps/console/monaco/_context_menu.ts new file mode 100644 index 00000000000000..f74e9d28142427 --- /dev/null +++ b/test/functional/apps/console/monaco/_context_menu.ts @@ -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 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const log = getService('log'); + const retry = getService('retry'); + const PageObjects = getPageObjects(['common', 'console']); + const browser = getService('browser'); + const toasts = getService('toasts'); + + describe('console context menu', function testContextMenu() { + before(async () => { + await PageObjects.common.navigateToApp('console'); + // Ensure that the text area can be interacted with + await PageObjects.console.closeHelpIfExists(); + await PageObjects.console.monaco.clearEditorText(); + await PageObjects.console.monaco.enterText('GET _search'); + }); + + it('should open context menu', async () => { + expect(await PageObjects.console.isContextMenuOpen()).to.be(false); + await PageObjects.console.clickContextMenu(); + expect(PageObjects.console.isContextMenuOpen()).to.be.eql(true); + }); + + it('should have options to copy as curl, open documentation, and auto indent', async () => { + await PageObjects.console.clickContextMenu(); + expect(PageObjects.console.isContextMenuOpen()).to.be.eql(true); + expect(PageObjects.console.isCopyAsCurlButtonVisible()).to.be.eql(true); + expect(PageObjects.console.isOpenDocumentationButtonVisible()).to.be.eql(true); + expect(PageObjects.console.isAutoIndentButtonVisible()).to.be.eql(true); + }); + + it('should copy as curl and show toast when copy as curl button is clicked', async () => { + await PageObjects.console.clickContextMenu(); + await PageObjects.console.clickCopyAsCurlButton(); + + const resultToast = await toasts.getElementByIndex(1); + const toastText = await resultToast.getVisibleText(); + + if (toastText.includes('Write permission denied')) { + log.debug('Write permission denied, skipping test'); + return; + } + + expect(toastText).to.be('Request copied as cURL'); + + const canReadClipboard = await browser.checkBrowserPermission('clipboard-read'); + if (canReadClipboard) { + const clipboardText = await browser.getClipboardValue(); + expect(clipboardText).to.contain('curl -XGET'); + } + }); + + it('should open documentation when open documentation button is clicked', async () => { + await PageObjects.console.clickContextMenu(); + await PageObjects.console.clickOpenDocumentationButton(); + + await retry.tryForTime(10000, async () => { + await browser.switchTab(1); + }); + + // Retry until the documentation is loaded + await retry.try(async () => { + const url = await browser.getCurrentUrl(); + expect(url).to.contain('search-search.html'); + }); + + // Close the documentation tab + await browser.closeCurrentWindow(); + await browser.switchTab(0); + }); + + // not implemented yet for monaco https://github.com/elastic/kibana/issues/185891 + it.skip('should toggle auto indent when auto indent button is clicked', async () => { + await PageObjects.console.clearTextArea(); + await PageObjects.console.enterRequest('GET _search\n{"query": {"match_all": {}}}'); + await PageObjects.console.clickContextMenu(); + await PageObjects.console.clickAutoIndentButton(); + // Retry until the request is auto indented + await retry.try(async () => { + const request = await PageObjects.console.getRequest(); + expect(request).to.be.eql('GET _search\n{\n "query": {\n "match_all": {}\n }\n}'); + }); + + await PageObjects.console.clickContextMenu(); + // Click the auto-indent button again to condense request + await PageObjects.console.clickAutoIndentButton(); + // Retry until the request is condensed + await retry.try(async () => { + const request = await PageObjects.console.getRequest(); + expect(request).to.be.eql('GET _search\n{"query":{"match_all":{}}}'); + }); + }); + }); +} diff --git a/test/functional/apps/console/monaco/_misc_console_behavior.ts b/test/functional/apps/console/monaco/_misc_console_behavior.ts new file mode 100644 index 00000000000000..bc179ccc83208a --- /dev/null +++ b/test/functional/apps/console/monaco/_misc_console_behavior.ts @@ -0,0 +1,129 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const retry = getService('retry'); + const browser = getService('browser'); + const PageObjects = getPageObjects(['common', 'console', 'header']); + + describe('misc console behavior', function testMiscConsoleBehavior() { + this.tags('includeFirefox'); + before(async () => { + await browser.setWindowSize(1200, 800); + await PageObjects.common.navigateToApp('console'); + // Ensure that the text area can be interacted with + await PageObjects.console.closeHelpIfExists(); + }); + + beforeEach(async () => { + await PageObjects.console.monaco.clearEditorText(); + }); + + describe('keyboard shortcuts', () => { + let tabCount = 1; + + after(async () => { + if (tabCount > 1) { + await browser.closeCurrentWindow(); + await browser.switchTab(0); + } + }); + + it('should execute the request when Ctrl+Enter is pressed', async () => { + await PageObjects.console.monaco.enterText('GET _search'); + await PageObjects.console.monaco.pressCtrlEnter(); + await retry.try(async () => { + const response = await PageObjects.console.monaco.getOutputText(); + expect(response).to.contain('"timed_out": false'); + }); + }); + + it('should auto indent current request when Ctrl+I is pressed', async () => { + await PageObjects.console.monaco.enterText('GET _search\n{"query": {"match_all": {}}}'); + await PageObjects.console.monaco.selectCurrentRequest(); + await PageObjects.console.monaco.pressCtrlI(); + await retry.waitFor('request to be auto indented', async () => { + const request = await PageObjects.console.monaco.getEditorText(); + return request === 'GET _search\n{\n "query": {\n "match_all": {}\n }\n}'; + }); + }); + + it('should jump to the previous request when Ctrl+Up is pressed', async () => { + await PageObjects.console.monaco.enterText('\nGET _search/foo'); + await PageObjects.console.monaco.enterText('\nGET _search/bar'); + await PageObjects.console.monaco.pressCtrlUp(); + await retry.waitFor('request to be selected', async () => { + const request = await PageObjects.console.monaco.getEditorTextAtLine(1); + return request === 'GET _search/foo'; + }); + }); + + it('should jump to the next request when Ctrl+Down is pressed', async () => { + await PageObjects.console.monaco.enterText('\nGET _search/foo'); + await PageObjects.console.monaco.enterText('\nGET _search/bar'); + await PageObjects.console.monaco.pressCtrlUp(); + await PageObjects.console.monaco.pressCtrlDown(); + await retry.waitFor('request to be selected', async () => { + const request = await PageObjects.console.monaco.getEditorTextAtLine(2); + return request === 'GET _search/bar'; + }); + }); + + // flaky + it.skip('should go to line number when Ctrl+L is pressed', async () => { + await PageObjects.console.monaco.enterText( + '\nGET _search/foo\n{\n "query": {\n "match_all": {} \n} \n}' + ); + await PageObjects.console.monaco.pressCtrlL(); + // Sleep to allow the line number input to be focused + await PageObjects.common.sleep(1000); + const alert = await browser.getAlert(); + await alert?.sendKeys('4'); + await alert?.accept(); + await PageObjects.common.sleep(1000); + expect(await PageObjects.console.monaco.getCurrentLineNumber()).to.be(4); + }); + + // flaky + it.skip('should open documentation when Ctrl+/ is pressed', async () => { + await PageObjects.console.monaco.enterText('GET _search'); + await PageObjects.console.monaco.pressEscape(); + await PageObjects.console.monaco.pressCtrlSlash(); + await retry.tryForTime(10000, async () => { + await browser.switchTab(1); + tabCount++; + }); + + // Retry until the documentation is loaded + await retry.try(async () => { + const url = await browser.getCurrentUrl(); + expect(url).to.contain('search-search.html'); + }); + }); + }); + + describe('customizable font size', () => { + // flaky + it.skip('should allow the font size to be customized', async () => { + await PageObjects.console.setFontSizeSetting(20); + await retry.try(async () => { + // the settings are not applied synchronously, so we retry for a time + expect(await PageObjects.console.monaco.getFontSize()).to.be('20px'); + }); + + await PageObjects.console.setFontSizeSetting(24); + await retry.try(async () => { + // the settings are not applied synchronously, so we retry for a time + expect(await PageObjects.console.monaco.getFontSize()).to.be('24px'); + }); + }); + }); + }); +} diff --git a/test/functional/apps/console/monaco/_settings.ts b/test/functional/apps/console/monaco/_settings.ts new file mode 100644 index 00000000000000..f998a281b560dc --- /dev/null +++ b/test/functional/apps/console/monaco/_settings.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 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const log = getService('log'); + const PageObjects = getPageObjects(['common', 'console']); + + describe('console settings', function testSettings() { + this.tags('includeFirefox'); + before(async () => { + log.debug('navigateTo console'); + await PageObjects.common.navigateToApp('console'); + // Ensure that the text area can be interacted with + await PageObjects.console.closeHelpIfExists(); + await PageObjects.console.monaco.clearEditorText(); + }); + + it('displays the a11y overlay', async () => { + await PageObjects.console.monaco.pressEscape(); + const isOverlayVisible = await PageObjects.console.monaco.isA11yOverlayVisible(); + expect(isOverlayVisible).to.be(true); + }); + + it('disables the a11y overlay via settings', async () => { + await PageObjects.console.openSettings(); + await PageObjects.console.toggleA11yOverlaySetting(); + + await PageObjects.console.monaco.pressEscape(); + const isOverlayVisible = await PageObjects.console.monaco.isA11yOverlayVisible(); + expect(isOverlayVisible).to.be(false); + }); + }); +} diff --git a/test/functional/apps/console/monaco/_text_input.ts b/test/functional/apps/console/monaco/_text_input.ts new file mode 100644 index 00000000000000..b238a557bbb382 --- /dev/null +++ b/test/functional/apps/console/monaco/_text_input.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const retry = getService('retry'); + const toasts = getService('toasts'); + const PageObjects = getPageObjects(['common', 'console', 'header']); + + describe('text input', function testTextInput() { + before(async () => { + await PageObjects.common.navigateToApp('console'); + await PageObjects.console.closeHelpIfExists(); + }); + + beforeEach(async () => { + await PageObjects.console.monaco.clearEditorText(); + }); + + describe('with a data URI in the load_from query', () => { + it('loads the data from the URI', async () => { + await PageObjects.common.navigateToApp('console', { + hash: '#/console?load_from=data:text/plain,BYUwNmD2Q', + }); + + await retry.try(async () => { + const actualRequest = await PageObjects.console.monaco.getEditorText(); + expect(actualRequest.trim()).to.eql('hello'); + }); + }); + + describe('with invalid data', () => { + it('shows a toast error', async () => { + await PageObjects.common.navigateToApp('console', { + hash: '#/console?load_from=data:text/plain,BYUwNmD2', + }); + + await retry.try(async () => { + expect(await toasts.getCount()).to.equal(1); + }); + }); + }); + }); + + // not yet implemented for monaco https://github.com/elastic/kibana/issues/186001 + describe.skip('copy/pasting cURL commands into the console', () => { + it('should convert cURL commands into the console request format', async () => { + await PageObjects.console.monaco.enterText( + `\n curl -XGET "http://localhost:9200/_search?pretty" -d'\n{"query": {"match_all": {}}}'` + ); + await PageObjects.console.monaco.copyRequestsToClipboard(); + await PageObjects.console.monaco.clearEditorText(); + await PageObjects.console.monaco.pasteClipboardValue(); + await retry.try(async () => { + const actualRequest = await PageObjects.console.monaco.getEditorText(); + expect(actualRequest.trim()).to.eql('GET /_search?pretty\n {"query": {"match_all": {}}}'); + }); + }); + }); + + describe('console history', () => { + const sendRequest = async (request: string) => { + await PageObjects.console.monaco.enterText(request); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + }; + + it('should show the history', async () => { + await sendRequest('GET /_search?pretty'); + await PageObjects.console.clickHistory(); + await retry.try(async () => { + const history = await PageObjects.console.getHistoryEntries(); + expect(history).to.eql(['/_search?pretty (a few seconds ago)']); + }); + + // Clear the history + await PageObjects.console.clickClearHistory(); + await PageObjects.console.closeHistory(); + }); + + it('should load a request from history', async () => { + await sendRequest('GET _search\n{"query": {"match_all": {}}}'); + await PageObjects.console.monaco.clearEditorText(); + await PageObjects.console.clickHistory(); + await PageObjects.console.loadRequestFromHistory(0); + await retry.try(async () => { + const actualRequest = await PageObjects.console.monaco.getEditorText(); + expect(actualRequest.trim()).to.eql( + 'GET _search\n{\n "query": {\n "match_all": {}\n }\n}' + ); + }); + }); + }); + }); +} diff --git a/test/functional/apps/console/monaco/_variables.ts b/test/functional/apps/console/monaco/_variables.ts new file mode 100644 index 00000000000000..5d8719e9ea4d3c --- /dev/null +++ b/test/functional/apps/console/monaco/_variables.ts @@ -0,0 +1,71 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ getService, getPageObjects }: FtrProviderContext) => { + const retry = getService('retry'); + const log = getService('log'); + const PageObjects = getPageObjects(['common', 'console', 'header']); + + describe('Console variables', function testConsoleVariables() { + // FLAKY on firefox: https://github.com/elastic/kibana/issues/157776 + // this.tags('includeFirefox'); + before(async () => { + log.debug('navigateTo console'); + await PageObjects.common.navigateToApp('console'); + await PageObjects.console.closeHelpIfExists(); + await PageObjects.console.monaco.clearEditorText(); + }); + + it('should allow creating a new variable', async () => { + await PageObjects.console.addNewVariable({ name: 'index1', value: 'test' }); + const variables = await PageObjects.console.getVariables(); + log.debug(variables); + expect(variables).to.contain('index1'); + }); + + it('should allow removing a variable', async () => { + await PageObjects.console.addNewVariable({ name: 'index2', value: 'test' }); + await PageObjects.console.removeVariables(); + const variables = await PageObjects.console.getVariables(); + expect(variables).to.eql([]); + }); + + describe('with variables in url', () => { + it('should send a successful request', async () => { + await PageObjects.console.addNewVariable({ name: 'index3', value: '_search' }); + await PageObjects.console.monaco.enterText('\n GET ${index3}'); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async () => { + const status = await PageObjects.console.getResponseStatus(); + expect(status).to.eql(200); + }); + }); + }); + + describe('with variables in request body', () => { + // bug in monaco https://github.com/elastic/kibana/issues/185999 + it.skip('should send a successful request', async () => { + await PageObjects.console.addNewVariable({ name: 'query1', value: '{"match_all": {}}' }); + await PageObjects.console.monaco.enterText('\n GET _search\n'); + await PageObjects.console.monaco.enterText(`{\n\t"query": "\${query1}"`); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async () => { + const status = await PageObjects.console.getResponseStatus(); + expect(status).to.eql(200); + }); + }); + }); + }); +}; diff --git a/test/functional/apps/console/monaco/_vector_tile.ts b/test/functional/apps/console/monaco/_vector_tile.ts new file mode 100644 index 00000000000000..4c00c5345c92fc --- /dev/null +++ b/test/functional/apps/console/monaco/_vector_tile.ts @@ -0,0 +1,51 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'console', 'header', 'home']); + const retry = getService('retry'); + const security = getService('security'); + + describe('console vector tiles response validation', function describeIndexTests() { + before(async () => { + await security.testUser.setRoles(['kibana_admin', 'kibana_sample_admin']); + await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', { + useActualUrl: true, + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.home.addSampleDataSet('logs'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.common.navigateToApp('console'); + await PageObjects.console.closeHelpIfExists(); + await PageObjects.console.monaco.clearEditorText(); + }); + + it('should validate response', async () => { + await PageObjects.console.monaco.enterText( + `GET kibana_sample_data_logs/_mvt/geo.coordinates/0/0/0` + ); + await PageObjects.console.clickPlay(); + await retry.try(async () => { + const actualResponse = await PageObjects.console.monaco.getOutputText(); + expect(actualResponse).to.contain('"meta": ['); + }); + }); + + after(async () => { + await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', { + useActualUrl: true, + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.home.removeSampleDataSet('logs'); + await security.testUser.restoreDefaults(); + }); + }); +} diff --git a/test/functional/apps/console/monaco/_xjson.ts b/test/functional/apps/console/monaco/_xjson.ts new file mode 100644 index 00000000000000..8f0a8d368ed060 --- /dev/null +++ b/test/functional/apps/console/monaco/_xjson.ts @@ -0,0 +1,118 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ getService, getPageObjects }: FtrProviderContext) => { + const retry = getService('retry'); + const PageObjects = getPageObjects(['common', 'console', 'header']); + + describe('XJSON', function testXjson() { + this.tags('includeFirefox'); + before(async () => { + await PageObjects.common.navigateToApp('console'); + await PageObjects.console.closeHelpIfExists(); + }); + + beforeEach(async () => { + await PageObjects.console.monaco.clearEditorText(); + }); + + const executeRequest = async (request = '\n GET _search') => { + await PageObjects.console.monaco.enterText(request); + await PageObjects.console.clickPlay(); + await PageObjects.header.waitUntilLoadingHasFinished(); + }; + + describe('inline http request', () => { + it('should not have validation errors', async () => { + await PageObjects.console.monaco.enterText('\n GET foo/bar'); + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(false); + }); + + it('should have validation error for invalid method', async () => { + await PageObjects.console.monaco.enterText('\n FOO foo/bar'); + // Retry because the error marker is not always immediately visible. + await retry.try(async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(true); + }); + }); + + it('should have validation error for invalid path', async () => { + await PageObjects.console.monaco.enterText('\n GET'); + // Retry because the error marker is not always immediately visible. + await retry.try(async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(true); + }); + }); + + it('should have validation error for invalid body', async () => { + await PageObjects.console.monaco.enterText('\n POST foo/bar\n {"foo": "bar"'); + // Retry because the error marker is not always immediately visible. + await retry.try(async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(true); + }); + }); + + it('should not trigger error for multiple bodies for _msearch requests', async () => { + await PageObjects.console.monaco.enterText( + '\nGET foo/_msearch \n{}\n{"query": {"match_all": {}}}\n{"index": "bar"}\n{"query": {"match_all": {}}}' + ); + // Retry until typing is finished. + await retry.try(async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(false); + }); + }); + + it('should not trigger validation errors for multiple JSON blocks', async () => { + await PageObjects.console.monaco.enterText('\nPOST test/doc/1 \n{\n "foo": "bar"\n}'); + await PageObjects.console.monaco.enterText('\nPOST test/doc/2 \n{\n "foo": "baz"\n}'); + await PageObjects.console.monaco.enterText('\nPOST test/doc/3 \n{\n "foo": "qux"\n}'); + // Retry until typing is finished. + await retry.try(async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(false); + }); + }); + + it('should allow escaping quotation mark by wrapping it in triple quotes', async () => { + await PageObjects.console.monaco.enterText( + '\nPOST test/_doc/1 \n{\n "foo": """look "escaped" quotes"""\n}' + ); + // Retry until typing is finished and validation errors are gone. + await retry.try(async () => { + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(false); + }); + }); + + it('should allow inline comments in request url row', async () => { + await executeRequest('\n GET _search // inline comment'); + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(false); + expect(await PageObjects.console.getResponseStatus()).to.eql(200); + }); + + it('should allow inline comments in request body', async () => { + await executeRequest( + '\n GET _search \n{\n "query": {\n "match_all": {} // inline comment\n}\n}' + ); + expect(await PageObjects.console.monaco.hasInvalidSyntax()).to.be(false); + expect(await PageObjects.console.getResponseStatus()).to.eql(200); + }); + + it('should print warning for deprecated request', async () => { + await executeRequest('\nGET .kibana'); + expect(await PageObjects.console.monaco.responseHasDeprecationWarning()).to.be(true); + }); + + it('should not print warning for non-deprecated request', async () => { + await executeRequest('\n GET _search'); + expect(await PageObjects.console.monaco.responseHasDeprecationWarning()).to.be(false); + }); + }); + }); +}; diff --git a/test/functional/apps/console/config.ts b/test/functional/apps/console/monaco/config.ts similarity index 87% rename from test/functional/apps/console/config.ts rename to test/functional/apps/console/monaco/config.ts index f295f1b8264922..13fd8b21c9162e 100644 --- a/test/functional/apps/console/config.ts +++ b/test/functional/apps/console/monaco/config.ts @@ -7,10 +7,10 @@ */ import { FtrConfigProviderContext } from '@kbn/test'; -import { configureHTTP2 } from '../../../common/configure_http2'; +import { configureHTTP2 } from '../../../../common/configure_http2'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { - const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); return configureHTTP2({ ...functionalConfig.getAll(), diff --git a/test/functional/apps/console/monaco/index.ts b/test/functional/apps/console/monaco/index.ts new file mode 100644 index 00000000000000..7274118daaafe9 --- /dev/null +++ b/test/functional/apps/console/monaco/index.ts @@ -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 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 { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const browser = getService('browser'); + const config = getService('config'); + + describe('console app', function () { + before(async function () { + await browser.setWindowSize(1300, 1100); + }); + if (config.get('esTestCluster.ccs')) { + loadTestFile(require.resolve('./_console_ccs')); + } else { + loadTestFile(require.resolve('./_console')); + loadTestFile(require.resolve('./_autocomplete')); + loadTestFile(require.resolve('./_vector_tile')); + loadTestFile(require.resolve('./_comments')); + loadTestFile(require.resolve('./_variables')); + loadTestFile(require.resolve('./_xjson')); + loadTestFile(require.resolve('./_misc_console_behavior')); + loadTestFile(require.resolve('./_context_menu')); + loadTestFile(require.resolve('./_text_input')); + loadTestFile(require.resolve('./_settings')); + } + }); +} diff --git a/test/functional/apps/dashboard_elements/controls/common/config.ts b/test/functional/apps/dashboard_elements/controls/common/config.ts index 60497ce2dae414..7e7e9ada1644d8 100644 --- a/test/functional/apps/dashboard_elements/controls/common/config.ts +++ b/test/functional/apps/dashboard_elements/controls/common/config.ts @@ -17,5 +17,13 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { junit: { reportName: 'Dashboard Elements - Controls tests', }, + kbnTestServer: { + ...functionalConfig.get('kbnTestServer'), + serverArgs: [ + ...functionalConfig.get('kbnTestServer.serverArgs'), + // disabling the monaco editor to run tests for ace + `--console.dev.enableMonaco=false`, + ], + }, }; } diff --git a/test/functional/apps/dashboard_elements/controls/options_list/config.ts b/test/functional/apps/dashboard_elements/controls/options_list/config.ts index c55987afa55707..150da945a12039 100644 --- a/test/functional/apps/dashboard_elements/controls/options_list/config.ts +++ b/test/functional/apps/dashboard_elements/controls/options_list/config.ts @@ -17,5 +17,13 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { junit: { reportName: 'Dashboard Elements - Controls Options List tests', }, + kbnTestServer: { + ...functionalConfig.get('kbnTestServer'), + serverArgs: [ + ...functionalConfig.get('kbnTestServer.serverArgs'), + // disabling the monaco editor to run tests for ace + `--console.dev.enableMonaco=false`, + ], + }, }; } diff --git a/test/functional/config.ccs.ts b/test/functional/config.ccs.ts index cea1de2be83164..506f57c72d1839 100644 --- a/test/functional/config.ccs.ts +++ b/test/functional/config.ccs.ts @@ -20,7 +20,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { testFiles: [ require.resolve('./apps/dashboard/group3'), require.resolve('./apps/discover/ccs_compatibility'), - require.resolve('./apps/console/_console_ccs'), + require.resolve('./apps/console/monaco/_console_ccs'), require.resolve('./apps/management/ccs_compatibility'), require.resolve('./apps/getting_started'), ], diff --git a/test/functional/firefox/console.config.ts b/test/functional/firefox/console.config.ts index 420eee1f438cb1..96141382047d05 100644 --- a/test/functional/firefox/console.config.ts +++ b/test/functional/firefox/console.config.ts @@ -16,7 +16,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { return { ...baseConfig.getAll(), - testFiles: [require.resolve('../apps/console')], + testFiles: [require.resolve('../apps/console/monaco')], junit: { reportName: 'Firefox UI Functional Tests - Console', diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index 3fdc1e8ab0f747..84267de85a5957 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -18,6 +18,166 @@ export class ConsolePageObject extends FtrService { private readonly common = this.ctx.getPageObject('common'); private readonly browser = this.ctx.getService('browser'); + public monaco = { + getTextArea: async () => { + const codeEditor = await this.testSubjects.find('consoleMonacoEditor'); + return await codeEditor.findByTagName('textarea'); + }, + getEditorText: async () => { + const codeEditor = await this.testSubjects.find('consoleMonacoEditor'); + const editorViewDiv = await codeEditor.findByClassName('view-lines'); + return await editorViewDiv.getVisibleText(); + }, + getEditorTextAtLine: async (line: number) => { + const codeEditor = await this.testSubjects.find('consoleMonacoEditor'); + const editorViewDiv = await codeEditor.findAllByClassName('view-line'); + return await editorViewDiv[line].getVisibleText(); + }, + getCurrentLineNumber: async () => { + const textArea = await this.monaco.getTextArea(); + const styleAttribute = (await textArea.getAttribute('style')) ?? ''; + const height = parseFloat(styleAttribute.replace(/.*height: ([+-]?\d+(\.\d+)?).*/, '$1')); + const top = parseFloat(styleAttribute.replace(/.*top: ([+-]?\d+(\.\d+)?).*/, '$1')); + // calculate the line number by dividing the top position by the line height + // and adding 1 because line numbers start at 1 + return Math.ceil(top / height) + 1; + }, + clearEditorText: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.clickMouseButton(); + await textArea.clearValueWithKeyboard(); + }, + getOutputText: async () => { + const outputPanel = await this.testSubjects.find('consoleMonacoOutput'); + const outputViewDiv = await outputPanel.findByClassName('monaco-scrollable-element'); + return await outputViewDiv.getVisibleText(); + }, + pressEnter: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys(Key.ENTER); + }, + enterText: async (text: string) => { + const textArea = await this.monaco.getTextArea(); + await textArea.type(text); + }, + promptAutocomplete: async (letter = 'b') => { + const textArea = await this.monaco.getTextArea(); + await textArea.type(letter); + await this.retry.waitFor('autocomplete to be visible', () => + this.monaco.isAutocompleteVisible() + ); + }, + isAutocompleteVisible: async () => { + const element = await this.find.byClassName('suggest-widget').catch(() => null); + if (!element) return false; + + const attribute = await element.getAttribute('style'); + return !attribute?.includes('display: none;'); + }, + getAutocompleteSuggestion: async (index: number) => { + const suggestionsWidget = await this.find.byClassName('suggest-widget'); + const suggestions = await suggestionsWidget.findAllByClassName('monaco-list-row'); + const label = await suggestions[index].findByClassName('label-name'); + return label.getVisibleText(); + }, + pressUp: async (shift: boolean = false) => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys(shift ? [Key.SHIFT, Key.UP] : Key.UP); + }, + pressDown: async (shift: boolean = false) => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys(shift ? [Key.SHIFT, Key.DOWN] : Key.DOWN); + }, + pressRight: async (shift: boolean = false) => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys(shift ? [Key.SHIFT, Key.RIGHT] : Key.RIGHT); + }, + pressLeft: async (shift: boolean = false) => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys(shift ? [Key.SHIFT, Key.LEFT] : Key.LEFT); + }, + pressCtrlSpace: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys([ + Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], + Key.SPACE, + ]); + }, + pressCtrlEnter: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys([ + Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], + Key.ENTER, + ]); + }, + pressCtrlI: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys([Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], 'i']); + }, + pressCtrlUp: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys([ + Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], + Key.UP, + ]); + }, + pressCtrlDown: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys([ + Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], + Key.DOWN, + ]); + }, + pressCtrlL: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys([Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], 'l']); + }, + pressCtrlSlash: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys([Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], '/']); + }, + pressEscape: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys(Key.ESCAPE); + }, + selectAllRequests: async () => { + const textArea = await this.monaco.getTextArea(); + const selectionKey = Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL']; + await textArea.pressKeys([selectionKey, 'a']); + }, + getEditor: async () => { + return await this.testSubjects.find('consoleMonacoEditor'); + }, + hasInvalidSyntax: async () => { + return await this.find.existsByCssSelector('.squiggly-error'); + }, + responseHasDeprecationWarning: async () => { + const response = await this.monaco.getOutputText(); + return response.trim().startsWith('#!'); + }, + selectCurrentRequest: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.clickMouseButton(); + }, + getFontSize: async () => { + const codeEditor = await this.testSubjects.find('consoleMonacoEditor'); + const editorViewDiv = await codeEditor.findByClassName('view-line'); + return await editorViewDiv.getComputedStyle('font-size'); + }, + pasteClipboardValue: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys([Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], 'v']); + }, + copyRequestsToClipboard: async () => { + const textArea = await this.monaco.getTextArea(); + await textArea.pressKeys([Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], 'a']); + await textArea.pressKeys([Key[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'], 'c']); + }, + isA11yOverlayVisible: async () => { + return await this.testSubjects.exists('codeEditorAccessibilityOverlay'); + }, + }; + public async getVisibleTextFromAceEditor(editor: WebElementWrapper) { const lines = await editor.findAllByClassName('ace_line_group'); const linesText = await Promise.all(lines.map(async (line) => await line.getVisibleText())); diff --git a/test/tsconfig.json b/test/tsconfig.json index 33a192fc996c69..0f120b831abe73 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -72,5 +72,6 @@ "@kbn/ftr-common-functional-ui-services", "@kbn/monaco", "@kbn/search-types", + "@kbn/console-plugin", ] } diff --git a/x-pack/test/functional/apps/reporting_management/config.ts b/x-pack/test/functional/apps/reporting_management/config.ts index d0d07ff2002816..af7abdc5122e1c 100644 --- a/x-pack/test/functional/apps/reporting_management/config.ts +++ b/x-pack/test/functional/apps/reporting_management/config.ts @@ -13,5 +13,13 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { return { ...functionalConfig.getAll(), testFiles: [require.resolve('.')], + kbnTestServer: { + ...functionalConfig.get('kbnTestServer'), + serverArgs: [ + ...functionalConfig.get('kbnTestServer.serverArgs'), + // disabling the monaco editor to run tests for ace + `--console.dev.enableMonaco=false`, + ], + }, }; } From bdef3aed2bfab93070fb751f1913761bff0e593f Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Wed, 19 Jun 2024 08:57:00 -0700 Subject: [PATCH 101/123] [HTTP/OAS] Add makefile to oas_docs (#185911) --- oas_docs/.spectral.yaml | 103 + oas_docs/README.md | 4 + oas_docs/kibana.info.serverless.yaml | 47 + oas_docs/kibana.serverless.yaml | 7394 ++++++++++++++++++++++++++ oas_docs/makefile | 29 + 5 files changed, 7577 insertions(+) create mode 100644 oas_docs/.spectral.yaml create mode 100644 oas_docs/README.md create mode 100644 oas_docs/kibana.info.serverless.yaml create mode 100644 oas_docs/kibana.serverless.yaml create mode 100644 oas_docs/makefile diff --git a/oas_docs/.spectral.yaml b/oas_docs/.spectral.yaml new file mode 100644 index 00000000000000..b328e320e23ebc --- /dev/null +++ b/oas_docs/.spectral.yaml @@ -0,0 +1,103 @@ +extends: ["spectral:oas"] +rules: +# Built-in rules + # Descriptions + oas3-parameter-description: warn + oas2-parameter-description: warn + tag-description: info + # Document info + info-contact: info + info-description: warn + info-license: warn + # Examples + oas3-valid-media-example: false + oas3-valid-schema-example: false + oas2-valid-media-example: false + # Operations + operation-operationId: false + operation-operationId-unique: false + operation-operationId-valid-in-url: false + operation-tag-defined: warn + operation-tags: warn + # Responses + operation-success-response: warn + # Schema + oas3-schema: error + oas2-schema: error + # Tags + openapi-tags: warn + openapi-tags-alphabetical: info + # Turn off some built-in rules + operation-description: false + operation-singular-tag: false +# Custom rules + # Descriptions + avoid-problematic-words: + description: Ban certain words from descriptions + message: "Use appropriate replacements for problematic terms" + severity: warn + given: "$..*.description" + then: + function: pattern + functionOptions: + notMatch: /(blacklist|whitelist|execute|kill)/i + # Examples + operation-success-examples: + formats: ["oas3_1"] + description: Response code 200 should have at least one example. + message: "Each response body should have a realistic example. It must not contain any sensitive or confidential data." + severity: info + given: $.paths[*].[*].responses.[200].content.[application/json] + then: + field: examples + function: defined + # Extensions + internal-extension: + description: Operations should not have x-internal extension. + message: "Do not publish x-internal operations" + severity: error + given: $.paths[*].[get,put,post,delete,options,head,patch,trace] + then: + field: x-internal + function: undefined + # Operations + operation-summary: + description: Operations should have summaries. + message: "Each operation should have a summary" + severity: error + recommended: true + given: $.paths[*].[get,put,post,delete,options,head,patch,trace] + then: + field: summary + function: defined + operation-summary-length: + description: Operation summary should be between 5 and 45 characters + given: "$.paths[*].[get,put,post,delete,options,head,patch,trace]" + then: + field: summary + function: length + functionOptions: + max: 45 + min: 5 + severity: warn + simple-verbs-in-summary: + given: + - "$.paths[*][*].summary" + then: + function: pattern + functionOptions: + notMatch: "Retrieve|Return|List *" + severity: warn + description: Summaries should use common verbs. + message: "Summaries should use common verbs like Get, Update, Delete whenever possible" + # NOTE: This one hiccups on acronyms so perhaps too noisy + # docs-operation-summary-sentence-case: + # description: Operation summary should be sentence cased + # given: "$.paths[*].[get,put,post,delete,options,head,patch,trace]" + # then: + # field: summary + # function: pattern + # functionOptions: + # match: /^[A-Z]+[^A-Z]+$/ + # severity: warn + diff --git a/oas_docs/README.md b/oas_docs/README.md new file mode 100644 index 00000000000000..70e39571c0af64 --- /dev/null +++ b/oas_docs/README.md @@ -0,0 +1,4 @@ +The `bundle.json` and `bundle.serverless.json` files are generated automatically. + +The `kibana.openapi.serverless.yaml` file is a temporary OpenAPI document created by joining some manually-maintained files. +To create it and lint it, run `make api-docs` and `make api-docs-lint`. \ No newline at end of file diff --git a/oas_docs/kibana.info.serverless.yaml b/oas_docs/kibana.info.serverless.yaml new file mode 100644 index 00000000000000..c96325cf7c75d5 --- /dev/null +++ b/oas_docs/kibana.info.serverless.yaml @@ -0,0 +1,47 @@ +openapi: 3.0.3 +info: + title: Kibana Serverless APIs + description: | + The Kibana REST APIs for Elastic serverless enable you to manage resources + such as connectors, data views, and saved objects. The API calls are + stateless. Each request that you make happens in isolation from other calls + and must include all of the necessary information for Kibana to fulfill the + request. API requests return JSON output, which is a format that is + machine-readable and works well for automation. + + To interact with Kibana APIs, use the following operations: + + - GET: Fetches the information. + - POST: Adds new information. + - PUT: Updates the existing information. + - DELETE: Removes the information. + + You can prepend any Kibana API endpoint with `kbn:` and run the request in + **Dev Tools → Console**. For example: + + ``` + GET kbn:/api/data_views + ``` + version: "1.0.2" + license: + name: Elastic License 2.0 + url: https://www.elastic.co/licensing/elastic-license + contact: + name: Kibana Team +# servers: +# - url: https://{kibana_url} +# variables: +# kibana_url: +# default: localhost:5601 +# security: +# - apiKeyAuth: [] +# components: +# securitySchemes: +# apiKeyAuth: +# type: apiKey +# in: header +# name: Authorization +# description: > +# These APIs use key-based authentication. +# You must create an API key and use the encoded value in the request header. +# For example: `Authorization: ApiKey base64AccessApiKey` \ No newline at end of file diff --git a/oas_docs/kibana.serverless.yaml b/oas_docs/kibana.serverless.yaml new file mode 100644 index 00000000000000..d7b5512e96099e --- /dev/null +++ b/oas_docs/kibana.serverless.yaml @@ -0,0 +1,7394 @@ +openapi: 3.0.3 +info: + title: Kibana Serverless APIs + description: | + The Kibana REST APIs for Elastic serverless enable you to manage resources + such as connectors, data views, and saved objects. The API calls are + stateless. Each request that you make happens in isolation from other calls + and must include all of the necessary information for Kibana to fulfill the + request. API requests return JSON output, which is a format that is + machine-readable and works well for automation. + + To interact with Kibana APIs, use the following operations: + + - GET: Fetches the information. + - POST: Adds new information. + - PUT: Updates the existing information. + - DELETE: Removes the information. + + You can prepend any Kibana API endpoint with `kbn:` and run the request in + **Dev Tools → Console**. For example: + + ``` + GET kbn:/api/data_views + ``` + version: 1.0.2 + license: + name: Elastic License 2.0 + url: https://www.elastic.co/licensing/elastic-license + contact: + name: Kibana Team +servers: + - url: https://{kibanaUrl} + variables: + kibanaUrl: + default: localhost:5601 + - url: https://{kibana_url} + variables: + kibana_url: + default: localhost:5601 + - url: / +tags: + - name: APM agent keys + description: > + Configure APM agent keys to authorize requests from APM agents to the APM + Server. + x-displayName: APM agent keys + - name: APM annotations + description: > + Annotate visualizations in the APM app with significant events. + Annotations enable you to easily see how events are impacting the + performance of your applications. + x-displayName: APM annotations + - name: connectors + description: Connector APIs enable you to create and manage connectors. + x-displayName: connectors + - name: data views + description: >- + Data view APIs enable you to manage data views, formerly known as Kibana + index patterns. + x-displayName: data views + - name: ml + description: Machine learning + x-displayName: ml + - name: saved objects + description: >- + Manage Kibana saved objects, including dashboards, visualizations, and + more. + x-displayName: saved objects +paths: + /api/apm/agent_keys: + post: + summary: Create an APM agent key + description: Create a new agent key for APM. + tags: + - APM agent keys + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + privileges: + type: array + items: + type: string + enum: + - event:write + - config_agent:read + responses: + '200': + description: Agent key created successfully + content: + application/json: + schema: + type: object + properties: + api_key: + type: string + expiration: + type: integer + format: int64 + id: + type: string + name: + type: string + encoded: + type: string + /api/apm/services/{serviceName}/annotation/search: + get: + summary: Search for annotations + description: Search for annotations related to a specific service. + tags: + - APM annotations + parameters: + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + - name: environment + in: query + required: false + description: The environment to filter annotations by + schema: + type: string + - name: start + in: query + required: false + description: The start date for the search + schema: + type: string + - name: end + in: query + required: false + description: The end date for the search + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + annotations: + type: array + items: + type: object + properties: + type: + type: string + enum: + - version + id: + type: string + '@timestamp': + type: number + text: + type: string + /api/apm/services/{serviceName}/annotation: + post: + summary: Create a service annotation + description: Create a new annotation for a specific service. + tags: + - APM annotations + parameters: + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + '@timestamp': + type: string + service: + type: object + properties: + version: + type: string + environment: + type: string + message: + type: string + tags: + type: array + items: + type: string + responses: + '200': + description: Annotation created successfully + content: + application/json: + schema: + type: object + properties: + _id: + type: string + _index: + type: string + _source: + type: object + properties: + annotation: + type: string + tags: + type: array + items: + type: string + message: + type: string + service: + type: object + properties: + name: + type: string + environment: + type: string + version: + type: string + event: + type: object + properties: + created: + type: string + '@timestamp': + type: string + /api/actions/connector: + post: + summary: Create a connector + operationId: createConnector + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_create_connector_request' + examples: + createEmailConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_email_connector_request + createIndexConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_index_connector_request + createWebhookConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_webhook_connector_request + createXmattersConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_xmatters_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + examples: + createEmailConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_email_connector_response + createIndexConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_index_connector_response + createWebhookConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_webhook_connector_response + createXmattersConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_xmatters_connector_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_apiKeyAuth: [] + /api/actions/connector/{connectorId}: + get: + summary: Get a connector information + operationId: getConnector + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_connector_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + examples: + getConnectorResponse: + $ref: '#/components/examples/Connectors_get_connector_response' + '401': + $ref: '#/components/responses/Connectors_401' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_apiKeyAuth: [] + delete: + summary: Delete a connector + operationId: deleteConnector + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_connector_id' + responses: + '204': + description: Indicates a successful call. + '401': + $ref: '#/components/responses/Connectors_401' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_apiKeyAuth: [] + post: + summary: Create a connector + operationId: createConnectorId + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - in: path + name: connectorId + description: > + A UUID v1 or v4 identifier for the connector. If you omit this + parameter, an identifier is randomly generated. + required: true + schema: + type: string + example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_create_connector_request' + examples: + createIndexConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_index_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + examples: + createIndexConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_index_connector_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_apiKeyAuth: [] + put: + summary: Update a connector + operationId: updateConnector + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_connector_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_update_connector_request' + examples: + updateIndexConnectorRequest: + $ref: >- + #/components/examples/Connectors_update_index_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + '400': + $ref: '#/components/responses/Connectors_401' + '401': + $ref: '#/components/responses/Connectors_401' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_apiKeyAuth: [] + /api/actions/connectors: + get: + summary: Get all connectors + operationId: getConnectors + tags: + - connectors + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: array + items: + $ref: >- + #/components/schemas/Connectors_connector_response_properties + examples: + getConnectorsResponse: + $ref: '#/components/examples/Connectors_get_connectors_response' + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_apiKeyAuth: [] + /api/actions/connector_types: + get: + summary: Get all connector types + operationId: getConnectorTypes + tags: + - connectors + parameters: + - in: query + name: feature_id + description: >- + A filter to limit the retrieved connector types to those that + support a specific feature (such as alerting or cases). + schema: + $ref: '#/components/schemas/Connectors_features' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + title: Get connector types response body properties + description: The properties vary for each connector type. + type: array + items: + type: object + properties: + enabled: + type: boolean + description: >- + Indicates whether the connector type is enabled in + Kibana. + example: true + enabled_in_config: + type: boolean + description: >- + Indicates whether the connector type is enabled in the + Kibana configuration file. + example: true + enabled_in_license: + type: boolean + description: >- + Indicates whether the connector is enabled in the + license. + example: true + id: + $ref: '#/components/schemas/Connectors_connector_types' + is_system_action_type: + type: boolean + example: false + minimum_license_required: + type: string + description: The license that is required to use the connector type. + example: basic + name: + type: string + description: The name of the connector type. + example: Index + supported_feature_ids: + type: array + description: The features that are supported by the connector type. + items: + $ref: '#/components/schemas/Connectors_features' + example: + - alerting + - cases + - siem + examples: + getConnectorTypesServerlessResponse: + $ref: >- + #/components/examples/Connectors_get_connector_types_generativeai_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/data_views: + get: + summary: Get all data views + operationId: getAllDataViews + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + namespaces: + type: array + items: + type: string + title: + type: string + typeMeta: + type: object + examples: + getAllDataViewsResponse: + $ref: '#/components/examples/Data_views_get_data_views_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view: + post: + summary: Create a data view + operationId: createDataView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_create_data_view_request_object' + examples: + createDataViewRequest: + $ref: '#/components/examples/Data_views_create_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view/{viewId}: + get: + summary: Get a data view + operationId: getDataView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + examples: + getDataViewResponse: + $ref: '#/components/examples/Data_views_get_data_view_response' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + delete: + summary: Delete a data view + operationId: deleteDataView + description: > + WARNING: When you delete a data view, it cannot be recovered. This + functionality is in technical preview and may be changed or removed in a + future release. Elastic will work to fix any issues, but features in + technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '204': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Update a data view + operationId: updateDataView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_update_data_view_request_object' + examples: + updateDataViewRequest: + $ref: '#/components/examples/Data_views_update_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/default: + get: + summary: Get the default data view identifier + operationId: getDefaultDataView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view_id: + type: string + examples: + getDefaultDataViewResponse: + $ref: >- + #/components/examples/Data_views_get_default_data_view_response + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Sets the default data view identifier + operationId: setDefaultDatailView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - data_view_id + properties: + data_view_id: + type: string + nullable: true + description: > + The data view identifier. NOTE: The API does not validate + whether it is a valid identifier. Use `null` to unset the + default data view. + force: + type: boolean + description: Update an existing default data view identifier. + default: false + examples: + setDefaultDataViewRequest: + $ref: '#/components/examples/Data_views_set_default_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view/{viewId}/fields: + post: + summary: Update data view fields metadata + operationId: updateFieldsMetadata + description: > + Update fields presentation metadata such as count, customLabel and + format. This functionality is in technical preview and may be changed or + removed in a future release. Elastic will work to fix any issues, but + features in technical preview are not subject to the support SLA of + official GA features. You can update multiple fields in one request. + Updates are merged with persisted metadata. To remove existing metadata, + specify null as the value. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - fields + properties: + fields: + description: The field object. + type: object + examples: + updateFieldsMetadataRequest: + $ref: '#/components/examples/Data_views_update_field_metadata_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view/{viewId}/runtime_field: + post: + summary: Create a runtime field + operationId: createRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - name + - runtimeField + properties: + name: + type: string + description: | + The name for a runtime field. + runtimeField: + type: object + description: | + The runtime field definition object. + examples: + createRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_create_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + put: + summary: Create or update a runtime field + operationId: createUpdateRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_space_id' + - name: viewId + in: path + description: | + The ID of the data view fields you want to update. + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - name + - runtimeField + properties: + name: + type: string + description: | + The name for a runtime field. + runtimeField: + type: object + description: | + The runtime field definition object. + examples: + updateRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_create_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view/{viewId}/runtime_field/{fieldName}: + get: + summary: Get a runtime field + operationId: getRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + examples: + getRuntimeFieldResponse: + $ref: '#/components/examples/Data_views_get_runtime_field_response' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + delete: + summary: Delete a runtime field from a data view + operationId: deleteRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Update a runtime field + operationId: updateRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - runtimeField + properties: + runtimeField: + type: object + description: | + The runtime field definition object. + + You can update following fields: + + - `type` + - `script` + examples: + updateRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_update_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views: + get: + summary: Get all data views in the default space + operationId: getAllDataViewsDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + namespaces: + type: array + items: + type: string + title: + type: string + typeMeta: + type: object + examples: + getAllDataViewsResponse: + $ref: '#/components/examples/Data_views_get_data_views_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view: + post: + summary: Create a data view in the default space + operationId: createDataViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_create_data_view_request_object' + examples: + createDataViewRequest: + $ref: '#/components/examples/Data_views_create_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view/{viewId}: + get: + summary: Get a data view in the default space + operationId: getDataViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_view_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + examples: + getDataViewResponse: + $ref: '#/components/examples/Data_views_get_data_view_response' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + delete: + summary: Delete a data view from the default space + operationId: deleteDataViewDefault + description: > + WARNING: When you delete a data view, it cannot be recovered. This + functionality is in technical preview and may be changed or removed in a + future release. Elastic will work to fix any issues, but features in + technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + responses: + '204': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Update a data view in the default space + operationId: updateDataViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_update_data_view_request_object' + examples: + updateDataViewRequest: + $ref: '#/components/examples/Data_views_update_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view/{viewId}/fields: + post: + summary: Update data view fields metadata in the default space + operationId: updateFieldsMetadataDefault + description: > + Update fields presentation metadata such as count, customLabel and + format. This functionality is in technical preview and may be changed or + removed in a future release. Elastic will work to fix any issues, but + features in technical preview are not subject to the support SLA of + official GA features. You can update multiple fields in one request. + Updates are merged with persisted metadata. To remove existing metadata, + specify null as the value. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - fields + properties: + fields: + description: The field object. + type: object + examples: + updateFieldsMetadataRequest: + $ref: '#/components/examples/Data_views_update_field_metadata_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view/{viewId}/runtime_field: + post: + summary: Create a runtime field in the default space + operationId: createRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - name + - runtimeField + properties: + name: + type: string + description: | + The name for a runtime field. + runtimeField: + type: object + description: | + The runtime field definition object. + examples: + createRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_create_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + put: + summary: Create or update a runtime field in the default space + operationId: createUpdateRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - name: viewId + in: path + description: | + The ID of the data view fields you want to update. + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - name + - runtimeField + properties: + name: + type: string + description: | + The name for a runtime field. + runtimeField: + type: object + description: | + The runtime field definition object. + examples: + updateRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_create_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view/{viewId}/runtime_field/{fieldName}: + get: + summary: Get a runtime field in the default space + operationId: getRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + examples: + getRuntimeFieldResponse: + $ref: '#/components/examples/Data_views_get_runtime_field_response' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + delete: + summary: Delete a runtime field from a data view in the default space + operationId: deleteRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + responses: + '200': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Update a runtime field in the default space + operationId: updateRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - runtimeField + properties: + runtimeField: + type: object + description: | + The runtime field definition object. + + You can update following fields: + + - `type` + - `script` + examples: + updateRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_update_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/default: + get: + summary: Get the default data view in the default space + operationId: getDefaultDataViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view_id: + type: string + examples: + getDefaultDataViewResponse: + $ref: >- + #/components/examples/Data_views_get_default_data_view_response + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Set the default data view in the default space + operationId: setDefaultDatailViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - data_view_id + properties: + data_view_id: + type: string + nullable: true + description: > + The data view identifier. NOTE: The API does not validate + whether it is a valid identifier. Use `null` to unset the + default data view. + force: + type: boolean + description: Update an existing default data view identifier. + default: false + examples: + setDefaultDataViewRequest: + $ref: '#/components/examples/Data_views_set_default_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/ml/saved_objects/sync: + get: + summary: Sync machine learning saved objects + description: > + Synchronizes Kibana saved objects for machine learning jobs and trained + models. This API runs automatically when you start Kibana and + periodically thereafter. + operationId: mlSync + tags: + - ml + parameters: + - $ref: '#/components/parameters/Machine_learning_APIs_simulateParam' + responses: + '200': + description: Indicates a successful call + content: + application/json: + schema: + $ref: '#/components/schemas/Machine_learning_APIs_mlSync200Response' + examples: + syncExample: + $ref: '#/components/examples/Machine_learning_APIs_mlSyncExample' + '401': + description: Authorization information is missing or invalid. + content: + application/json: + schema: + $ref: '#/components/schemas/Machine_learning_APIs_mlSync4xxResponse' + security: + - Machine_learning_APIs_apiKeyAuth: [] + /api/saved_objects/_export: + post: + summary: Export saved objects in the default space + operationId: exportSavedObjectsDefault + description: > + Retrieve sets of saved objects that you want to import into Kibana. + + You must include `type` or `objects` in the request body. + + + NOTE: The `savedObjects.maxImportExportSize` configuration setting + limits the number of saved objects which may be exported. + + + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Serverless_saved_objects_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + excludeExportDetails: + description: Do not add export details entry at the end of the stream. + type: boolean + default: false + includeReferencesDeep: + description: >- + Includes all of the referenced objects in the exported + objects. + type: boolean + objects: + description: A list of objects to export. + type: array + items: + type: object + type: + description: >- + The saved object types to include in the export. Use `*` to + export all the types. + oneOf: + - type: string + - type: array + items: + type: string + examples: + exportSavedObjectsRequest: + $ref: >- + #/components/examples/Serverless_saved_objects_export_objects_request + responses: + '200': + description: Indicates a successful call. + content: + application/x-ndjson: + schema: + type: object + additionalProperties: true + examples: + exportSavedObjectsResponse: + $ref: >- + #/components/examples/Serverless_saved_objects_export_objects_response + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Serverless_saved_objects_400_response' + security: + - Serverless_saved_objects_apiKeyAuth: [] + /api/saved_objects/_import: + post: + summary: Import saved objects in the default space + operationId: importSavedObjectsDefault + description: > + Create sets of Kibana saved objects from a file created by the export + API. + + Saved objects can be imported only into the same version, a newer minor + on the same major, or the next major. Exported saved objects are not + backwards compatible and cannot be imported into an older version of + Kibana. + + + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Serverless_saved_objects_kbn_xsrf' + - in: query + name: createNewCopies + schema: + type: boolean + required: false + description: > + Creates copies of saved objects, regenerates each object ID, and + resets the origin. When used, potential conflict errors are avoided. + NOTE: This option cannot be used with the `overwrite` and + `compatibilityMode` options. + - in: query + name: overwrite + schema: + type: boolean + required: false + description: > + Overwrites saved objects when they already exist. When used, + potential conflict errors are automatically resolved by overwriting + the destination object. NOTE: This option cannot be used with the + `createNewCopies` option. + - in: query + name: compatibilityMode + schema: + type: boolean + required: false + description: > + Applies various adjustments to the saved objects that are being + imported to maintain compatibility between different Kibana + versions. Use this option only if you encounter issues with imported + saved objects. NOTE: This option cannot be used with the + `createNewCopies` option. + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + description: > + A file exported using the export API. NOTE: The + `savedObjects.maxImportExportSize` configuration setting + limits the number of saved objects which may be included in + this file. Similarly, the + `savedObjects.maxImportPayloadBytes` setting limits the + overall size of the file that can be imported. + examples: + importObjectsRequest: + $ref: >- + #/components/examples/Serverless_saved_objects_import_objects_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: > + Indicates when the import was successfully completed. When + set to false, some objects may not have been created. For + additional information, refer to the `errors` and + `successResults` properties. + successCount: + type: integer + description: Indicates the number of successfully imported records. + errors: + type: array + items: + type: object + description: > + Indicates the import was unsuccessful and specifies the + objects that failed to import. + + + NOTE: One object may result in multiple errors, which + requires separate steps to resolve. For instance, a + `missing_references` error and conflict error. + successResults: + type: array + items: + type: object + description: > + Indicates the objects that are successfully imported, with + any metadata if applicable. + + + NOTE: Objects are created only when all resolvable errors + are addressed, including conflicts and missing references. + If objects are created as new copies, each entry in the + `successResults` array includes a `destinationId` + attribute. + examples: + importObjectsResponse: + $ref: >- + #/components/examples/Serverless_saved_objects_import_objects_response + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Serverless_saved_objects_400_response' + security: + - Serverless_saved_objects_apiKeyAuth: [] + /s/{spaceId}/api/saved_objects/_export: + post: + summary: Export saved objects + operationId: exportSavedObjects + description: > + Retrieves sets of saved objects that you want to import into Kibana. + + You must include `type` or `objects` in the request body. + + + NOTE: The `savedObjects.maxImportExportSize` configuration setting + limits the number of saved objects which may be exported. + + + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Serverless_saved_objects_kbn_xsrf' + - $ref: '#/components/parameters/Serverless_saved_objects_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: >- + #/components/schemas/Serverless_saved_objects_export_objects_request + examples: + exportSavedObjectsRequest: + $ref: >- + #/components/examples/Serverless_saved_objects_export_objects_request + responses: + '200': + description: Indicates a successful call. + content: + application/x-ndjson: + schema: + type: object + additionalProperties: true + examples: + exportSavedObjectsResponse: + $ref: >- + #/components/examples/Serverless_saved_objects_export_objects_response + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Serverless_saved_objects_400_response' + security: + - Serverless_saved_objects_apiKeyAuth: [] + /s/{spaceId}/api/saved_objects/_import: + post: + summary: Import saved objects + operationId: importSavedObjects + description: > + Creates sets of Kibana saved objects from a file created by the export + API. + + Saved objects can be imported only into the same version, a newer minor + on the same major, or the next major. Exported saved objects are not + backwards compatible and cannot be imported into an older version of + Kibana. + + + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Serverless_saved_objects_kbn_xsrf' + - $ref: '#/components/parameters/Serverless_saved_objects_space_id' + - $ref: '#/components/parameters/Serverless_saved_objects_compatibility_mode' + - $ref: '#/components/parameters/Serverless_saved_objects_create_new_copies' + - $ref: '#/components/parameters/Serverless_saved_objects_overwrite' + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: >- + #/components/schemas/Serverless_saved_objects_import_objects_request + examples: + importObjectsRequest: + $ref: >- + #/components/examples/Serverless_saved_objects_import_objects_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: >- + #/components/schemas/Serverless_saved_objects_200_import_objects_response + examples: + importObjectsResponse: + $ref: >- + #/components/examples/Serverless_saved_objects_import_objects_response + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Serverless_saved_objects_400_response' + security: + - Serverless_saved_objects_apiKeyAuth: [] +components: + securitySchemes: + Connectors_apiKeyAuth: + type: apiKey + in: header + name: Authorization + description: > + Serverless APIs support only key-based authentication. You must create + an API key and use the encoded value in the request header. For example: + 'Authorization: ApiKey base64AccessApiKey'. + Data_views_basicAuth: + type: http + scheme: basic + Data_views_apiKeyAuth: + type: apiKey + in: header + name: Authorization + description: > + Serverless APIs support only key-based authentication. You must create + an API key and use the encoded value in the request header. For example: + 'Authorization: ApiKey base64AccessApiKey'. + Machine_learning_APIs_apiKeyAuth: + type: apiKey + in: header + name: ApiKey + Serverless_saved_objects_apiKeyAuth: + type: apiKey + in: header + name: Authorization + description: > + Serverless APIs support only key-based authentication. You must create + an API key and use the encoded value in the request header. For example: + 'Authorization: ApiKey base64AccessApiKey'. + parameters: + Connectors_kbn_xsrf: + schema: + type: string + in: header + name: kbn-xsrf + description: Cross-site request forgery protection + required: true + Connectors_connector_id: + in: path + name: connectorId + description: An identifier for the connector. + required: true + schema: + type: string + example: df770e30-8b8b-11ed-a780-3b746c987a81 + Data_views_space_id: + in: path + name: spaceId + description: >- + An identifier for the space. If `/s/` and the identifier are omitted + from the path, the default space is used. + required: true + schema: + type: string + example: default + Data_views_kbn_xsrf: + schema: + type: string + in: header + name: kbn-xsrf + description: Cross-site request forgery protection + required: true + Data_views_view_id: + in: path + name: viewId + description: An identifier for the data view. + required: true + schema: + type: string + example: ff959d40-b880-11e8-a6d9-e546fe2bba5f + Data_views_field_name: + in: path + name: fieldName + description: The name of the runtime field. + required: true + schema: + type: string + example: hour_of_day + Machine_learning_APIs_simulateParam: + in: query + name: simulate + description: >- + When true, simulates the synchronization by returning only the list of + actions that would be performed. + required: false + schema: + type: boolean + example: 'true' + Serverless_saved_objects_kbn_xsrf: + schema: + type: string + in: header + name: kbn-xsrf + description: Cross-site request forgery protection + required: true + Serverless_saved_objects_space_id: + in: path + name: spaceId + description: >- + An identifier for the space. If `/s/` and the identifier are omitted + from the path, the default space is used. + required: true + schema: + type: string + example: default + Serverless_saved_objects_compatibility_mode: + in: query + name: compatibilityMode + schema: + type: boolean + required: false + description: > + Applies various adjustments to the saved objects that are being imported + to maintain compatibility between different Kibana versions. Use this + option only if you encounter issues with imported saved objects. NOTE: + This option cannot be used with the `createNewCopies` option. + Serverless_saved_objects_create_new_copies: + in: query + name: createNewCopies + schema: + type: boolean + required: false + description: > + Creates copies of saved objects, regenerates each object ID, and resets + the origin. When used, potential conflict errors are avoided. NOTE: This + option cannot be used with the `overwrite` and `compatibilityMode` + options. + Serverless_saved_objects_overwrite: + in: query + name: overwrite + schema: + type: boolean + required: false + description: > + Overwrites saved objects when they already exist. When used, potential + conflict errors are automatically resolved by overwriting the + destination object. NOTE: This option cannot be used with the + `createNewCopies` option. + schemas: + Connectors_create_connector_request_bedrock: + title: Create Amazon Bedrock connector request + description: >- + The Amazon Bedrock connector uses axios to send a POST request to Amazon + Bedrock. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_bedrock' + connector_type_id: + type: string + description: The type of connector. + enum: + - .bedrock + example: .bedrock + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_bedrock' + Connectors_create_connector_request_gemini: + title: Create Google Gemini connector request + description: >- + The Google Gemini connector uses axios to send a POST request to Google + Gemini. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_gemini' + connector_type_id: + type: string + description: The type of connector. + enum: + - .gemini + example: .gemini + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_gemini' + Connectors_create_connector_request_cases_webhook: + title: Create Webhook - Case Managment connector request + description: > + The Webhook - Case Management connector uses axios to send POST, PUT, + and GET requests to a case management RESTful API web service. + type: object + required: + - config + - connector_type_id + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_cases_webhook' + connector_type_id: + type: string + description: The type of connector. + enum: + - .cases-webhook + example: .cases-webhook + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_cases_webhook' + Connectors_create_connector_request_d3security: + title: Create D3 Security connector request + description: > + The connector uses axios to send a POST request to a D3 Security + endpoint. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_d3security' + connector_type_id: + type: string + description: The type of connector. + enum: + - .d3security + example: .d3security + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_d3security' + Connectors_create_connector_request_email: + title: Create email connector request + description: > + The email connector uses the SMTP protocol to send mail messages, using + an integration of Nodemailer. An exception is Microsoft Exchange, which + uses HTTP protocol for sending emails, Send mail. Email message text is + sent as both plain text and html text. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_email' + connector_type_id: + type: string + description: The type of connector. + enum: + - .email + example: .email + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_email' + Connectors_create_connector_request_genai: + title: Create OpenAI connector request + description: > + The OpenAI connector uses axios to send a POST request to either OpenAI + or Azure OpenAPI. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_genai' + connector_type_id: + type: string + description: The type of connector. + enum: + - .gen-ai + example: .gen-ai + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_genai' + Connectors_create_connector_request_index: + title: Create index connector request + description: The index connector indexes a document into Elasticsearch. + type: object + required: + - config + - connector_type_id + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_index' + connector_type_id: + type: string + description: The type of connector. + enum: + - .index + example: .index + name: + type: string + description: The display name for the connector. + example: my-connector + Connectors_create_connector_request_jira: + title: Create Jira connector request + description: The Jira connector uses the REST API v2 to create Jira issues. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_jira' + connector_type_id: + type: string + description: The type of connector. + enum: + - .jira + example: .jira + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_jira' + Connectors_create_connector_request_opsgenie: + title: Create Opsgenie connector request + description: The Opsgenie connector uses the Opsgenie alert API. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_opsgenie' + connector_type_id: + type: string + description: The type of connector. + enum: + - .opsgenie + example: .opsgenie + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_opsgenie' + Connectors_create_connector_request_pagerduty: + title: Create PagerDuty connector request + description: > + The PagerDuty connector uses the v2 Events API to trigger, acknowledge, + and resolve PagerDuty alerts. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_pagerduty' + connector_type_id: + type: string + description: The type of connector. + enum: + - .pagerduty + example: .pagerduty + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_pagerduty' + Connectors_create_connector_request_resilient: + title: Create IBM Resilient connector request + description: >- + The IBM Resilient connector uses the RESILIENT REST v2 to create IBM + Resilient incidents. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_resilient' + connector_type_id: + description: The type of connector. + type: string + example: .resilient + enum: + - .resilient + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_resilient' + Connectors_create_connector_request_sentinelone: + title: Create SentinelOne connector request + description: > + The SentinelOne connector communicates with SentinelOne Management + Console via REST API. This functionality is in technical preview and may + be changed or removed in a future release. Elastic will work to fix any + issues, but features in technical preview are not subject to the support + SLA of official GA features. + x-technical-preview: true + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_sentinelone' + connector_type_id: + type: string + description: The type of connector. + enum: + - .sentinelone + example: .sentinelone + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_sentinelone' + Connectors_create_connector_request_serverlog: + title: Create server log connector request + description: This connector writes an entry to the Kibana server log. + type: object + required: + - connector_type_id + - name + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .server-log + example: .server-log + name: + type: string + description: The display name for the connector. + example: my-connector + Connectors_create_connector_request_servicenow: + title: Create ServiceNow ITSM connector request + description: > + The ServiceNow ITSM connector uses the import set API to create + ServiceNow incidents. You can use the connector for rule actions and + cases. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow + example: .servicenow + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_create_connector_request_servicenow_itom: + title: Create ServiceNow ITOM connector request + description: > + The ServiceNow ITOM connector uses the event API to create ServiceNow + events. You can use the connector for rule actions. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow_itom' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow-itom + example: .servicenow-itom + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_create_connector_request_servicenow_sir: + title: Create ServiceNow SecOps connector request + description: > + The ServiceNow SecOps connector uses the import set API to create + ServiceNow security incidents. You can use the connector for rule + actions and cases. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow-sir + example: .servicenow-sir + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_create_connector_request_slack_api: + title: Create Slack connector request + description: The Slack connector uses an API method to send Slack messages. + type: object + required: + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_slack_api' + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack_api + example: .slack_api + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_slack_api' + Connectors_create_connector_request_slack_webhook: + title: Create Slack connector request + description: The Slack connector uses Slack Incoming Webhooks. + type: object + required: + - connector_type_id + - name + - secrets + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack + example: .slack + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_slack_webhook' + Connectors_create_connector_request_swimlane: + title: Create Swimlane connector request + description: >- + The Swimlane connector uses the Swimlane REST API to create Swimlane + records. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_swimlane' + connector_type_id: + type: string + description: The type of connector. + enum: + - .swimlane + example: .swimlane + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_swimlane' + Connectors_create_connector_request_teams: + title: Create Microsoft Teams connector request + description: The Microsoft Teams connector uses Incoming Webhooks. + type: object + required: + - connector_type_id + - name + - secrets + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .teams + example: .teams + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_teams' + Connectors_create_connector_request_tines: + title: Create Tines connector request + description: > + The Tines connector uses Tines Webhook actions to send events via POST + request. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_tines' + connector_type_id: + type: string + description: The type of connector. + enum: + - .tines + example: .tines + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_tines' + Connectors_create_connector_request_torq: + title: Create Torq connector request + description: > + The Torq connector uses a Torq webhook to trigger workflows with Kibana + actions. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_torq' + connector_type_id: + type: string + description: The type of connector. + enum: + - .torq + example: .torq + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_torq' + Connectors_create_connector_request_webhook: + title: Create Webhook connector request + description: > + The Webhook connector uses axios to send a POST or PUT request to a web + service. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_webhook' + connector_type_id: + type: string + description: The type of connector. + enum: + - .webhook + example: .webhook + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_webhook' + Connectors_create_connector_request_xmatters: + title: Create xMatters connector request + description: > + The xMatters connector uses the xMatters Workflow for Elastic to send + actionable alerts to on-call xMatters resources. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_xmatters' + connector_type_id: + type: string + description: The type of connector. + enum: + - .xmatters + example: .xmatters + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_xmatters' + Connectors_config_properties_bedrock: + title: Connector request properties for an Amazon Bedrock connector + description: Defines properties for connectors when type is `.bedrock`. + type: object + required: + - apiUrl + properties: + apiUrl: + type: string + description: The Amazon Bedrock request URL. + defaultModel: + type: string + description: > + The generative artificial intelligence model for Amazon Bedrock to + use. Current support is for the Anthropic Claude models. + default: anthropic.claude-3-sonnet-20240229-v1:0 + Connectors_secrets_properties_bedrock: + title: Connector secrets properties for an Amazon Bedrock connector + description: Defines secrets for connectors when type is `.bedrock`. + type: object + required: + - accessKey + - secret + properties: + accessKey: + type: string + description: The AWS access key for authentication. + secret: + type: string + description: The AWS secret for authentication. + Connectors_config_properties_gemini: + title: Connector request properties for an Google Gemini connector + description: Defines properties for connectors when type is `.gemini`. + type: object + required: + - apiUrl + - gcpRegion + - gcpProjectID + properties: + apiUrl: + type: string + description: The Google Gemini request URL. + defaultModel: + type: string + description: >- + The generative artificial intelligence model for Google Gemini to + use. + default: gemini-1.5-pro-preview-0409 + gcpRegion: + type: string + description: The GCP region where the Vertex AI endpoint enabled. + gcpProjectID: + type: string + description: The Google ProjectID that has Vertex AI endpoint enabled. + Connectors_secrets_properties_gemini: + title: Connector secrets properties for a Google Gemini connector + description: Defines secrets for connectors when type is `.gemini`. + type: object + required: + - credentialsJSON + properties: + credentialsJSON: + type: string + description: >- + The service account credentials JSON file. The service account + should have Vertex AI user IAM role assigned to it. + Connectors_config_properties_cases_webhook: + title: Connector request properties for Webhook - Case Management connector + required: + - createIncidentJson + - createIncidentResponseKey + - createIncidentUrl + - getIncidentResponseExternalTitleKey + - getIncidentUrl + - updateIncidentJson + - updateIncidentUrl + - viewIncidentUrl + description: Defines properties for connectors when type is `.cases-webhook`. + type: object + properties: + createCommentJson: + type: string + description: > + A JSON payload sent to the create comment URL to create a case + comment. You can use variables to add Kibana Cases data to the + payload. The required variable is `case.comment`. Due to Mustache + template variables (the text enclosed in triple braces, for example, + `{{{case.title}}}`), the JSON is not validated when you create the + connector. The JSON is validated once the Mustache variables have + been placed when the REST method runs. Manually ensure that the JSON + is valid, disregarding the Mustache variables, so the later + validation will pass. + example: '{"body": {{{case.comment}}}}' + createCommentMethod: + type: string + description: > + The REST API HTTP request method to create a case comment in the + third-party system. Valid values are `patch`, `post`, and `put`. + default: put + enum: + - patch + - post + - put + createCommentUrl: + type: string + description: > + The REST API URL to create a case comment by ID in the third-party + system. You can use a variable to add the external system ID to the + URL. If you are using the `xpack.actions.allowedHosts setting`, add + the hostname to the allowed hosts. + example: https://example.com/issue/{{{external.system.id}}}/comment + createIncidentJson: + type: string + description: > + A JSON payload sent to the create case URL to create a case. You can + use variables to add case data to the payload. Required variables + are `case.title` and `case.description`. Due to Mustache template + variables (which is the text enclosed in triple braces, for example, + `{{{case.title}}}`), the JSON is not validated when you create the + connector. The JSON is validated after the Mustache variables have + been placed when REST method runs. Manually ensure that the JSON is + valid to avoid future validation errors; disregard Mustache + variables during your review. + example: >- + {"fields": {"summary": {{{case.title}}},"description": + {{{case.description}}},"labels": {{{case.tags}}}}} + createIncidentMethod: + type: string + description: > + The REST API HTTP request method to create a case in the third-party + system. Valid values are `patch`, `post`, and `put`. + enum: + - patch + - post + - put + default: post + createIncidentResponseKey: + type: string + description: >- + The JSON key in the create external case response that contains the + case ID. + createIncidentUrl: + type: string + description: > + The REST API URL to create a case in the third-party system. If you + are using the `xpack.actions.allowedHosts` setting, add the hostname + to the allowed hosts. + getIncidentResponseExternalTitleKey: + type: string + description: >- + The JSON key in get external case response that contains the case + title. + getIncidentUrl: + type: string + description: > + The REST API URL to get the case by ID from the third-party system. + If you are using the `xpack.actions.allowedHosts` setting, add the + hostname to the allowed hosts. You can use a variable to add the + external system ID to the URL. Due to Mustache template variables + (the text enclosed in triple braces, for example, + `{{{case.title}}}`), the JSON is not validated when you create the + connector. The JSON is validated after the Mustache variables have + been placed when REST method runs. Manually ensure that the JSON is + valid, disregarding the Mustache variables, so the later validation + will pass. + example: https://example.com/issue/{{{external.system.id}}} + hasAuth: + type: boolean + description: >- + If true, a username and password for login type authentication must + be provided. + default: true + headers: + type: string + description: > + A set of key-value pairs sent as headers with the request URLs for + the create case, update case, get case, and create comment methods. + updateIncidentJson: + type: string + description: > + The JSON payload sent to the update case URL to update the case. You + can use variables to add Kibana Cases data to the payload. Required + variables are `case.title` and `case.description`. Due to Mustache + template variables (which is the text enclosed in triple braces, for + example, `{{{case.title}}}`), the JSON is not validated when you + create the connector. The JSON is validated after the Mustache + variables have been placed when REST method runs. Manually ensure + that the JSON is valid to avoid future validation errors; disregard + Mustache variables during your review. + example: >- + {"fields": {"summary": {{{case.title}}},"description": + {{{case.description}}},"labels": {{{case.tags}}}}} + updateIncidentMethod: + type: string + description: > + The REST API HTTP request method to update the case in the + third-party system. Valid values are `patch`, `post`, and `put`. + default: put + enum: + - patch + - post + - put + updateIncidentUrl: + type: string + description: > + The REST API URL to update the case by ID in the third-party system. + You can use a variable to add the external system ID to the URL. If + you are using the `xpack.actions.allowedHosts` setting, add the + hostname to the allowed hosts. + example: https://example.com/issue/{{{external.system.ID}}} + viewIncidentUrl: + type: string + description: > + The URL to view the case in the external system. You can use + variables to add the external system ID or external system title to + the URL. + example: >- + https://testing-jira.atlassian.net/browse/{{{external.system.title}}} + Connectors_secrets_properties_cases_webhook: + title: Connector secrets properties for Webhook - Case Management connector + type: object + properties: + password: + type: string + description: >- + The password for HTTP basic authentication. If `hasAuth` is set to + `true`, this property is required. + user: + type: string + description: >- + The username for HTTP basic authentication. If `hasAuth` is set to + `true`, this property is required. + Connectors_config_properties_d3security: + title: Connector request properties for a D3 Security connector + description: Defines properties for connectors when type is `.d3security`. + type: object + required: + - url + properties: + url: + type: string + description: > + The D3 Security API request URL. If you are using the + `xpack.actions.allowedHosts` setting, add the hostname to the + allowed hosts. + Connectors_secrets_properties_d3security: + title: Connector secrets properties for a D3 Security connector + description: Defines secrets for connectors when type is `.d3security`. + required: + - token + type: object + properties: + token: + type: string + description: The D3 Security token. + Connectors_config_properties_email: + title: Connector request properties for an email connector + description: Defines properties for connectors when type is `.email`. + required: + - from + type: object + properties: + clientId: + description: > + The client identifier, which is a part of OAuth 2.0 client + credentials authentication, in GUID format. If `service` is + `exchange_server`, this property is required. + type: string + nullable: true + from: + description: > + The from address for all emails sent by the connector. It must be + specified in `user@host-name` format. + type: string + hasAuth: + description: > + Specifies whether a user and password are required inside the + secrets configuration. + default: true + type: boolean + host: + description: > + The host name of the service provider. If the `service` is + `elastic_cloud` (for Elastic Cloud notifications) or one of + Nodemailer's well-known email service providers, this property is + ignored. If `service` is `other`, this property must be defined. + type: string + oauthTokenUrl: + type: string + nullable: true + port: + description: > + The port to connect to on the service provider. If the `service` is + `elastic_cloud` (for Elastic Cloud notifications) or one of + Nodemailer's well-known email service providers, this property is + ignored. If `service` is `other`, this property must be defined. + type: integer + secure: + description: > + Specifies whether the connection to the service provider will use + TLS. If the `service` is `elastic_cloud` (for Elastic Cloud + notifications) or one of Nodemailer's well-known email service + providers, this property is ignored. + type: boolean + service: + description: | + The name of the email service. + type: string + enum: + - elastic_cloud + - exchange_server + - gmail + - other + - outlook365 + - ses + tenantId: + description: > + The tenant identifier, which is part of OAuth 2.0 client credentials + authentication, in GUID format. If `service` is `exchange_server`, + this property is required. + type: string + nullable: true + Connectors_secrets_properties_email: + title: Connector secrets properties for an email connector + description: Defines secrets for connectors when type is `.email`. + type: object + properties: + clientSecret: + type: string + description: > + The Microsoft Exchange Client secret for OAuth 2.0 client + credentials authentication. It must be URL-encoded. If `service` is + `exchange_server`, this property is required. + password: + type: string + description: > + The password for HTTP basic authentication. If `hasAuth` is set to + `true`, this property is required. + user: + type: string + description: > + The username for HTTP basic authentication. If `hasAuth` is set to + `true`, this property is required. + Connectors_config_properties_genai_azure: + title: >- + Connector request properties for an OpenAI connector that uses Azure + OpenAI + description: > + Defines properties for connectors when type is `.gen-ai` and the API + provider is `Azure OpenAI'. + type: object + required: + - apiProvider + - apiUrl + properties: + apiProvider: + type: string + description: The OpenAI API provider. + enum: + - Azure OpenAI + apiUrl: + type: string + description: The OpenAI API endpoint. + Connectors_config_properties_genai_openai: + title: Connector request properties for an OpenAI connector + description: > + Defines properties for connectors when type is `.gen-ai` and the API + provider is `OpenAI'. + type: object + required: + - apiProvider + - apiUrl + properties: + apiProvider: + type: string + description: The OpenAI API provider. + enum: + - OpenAI + apiUrl: + type: string + description: The OpenAI API endpoint. + defaultModel: + type: string + description: The default model to use for requests. + Connectors_config_properties_genai: + title: Connector request properties for an OpenAI connector + description: Defines properties for connectors when type is `.gen-ai`. + oneOf: + - $ref: '#/components/schemas/Connectors_config_properties_genai_azure' + - $ref: '#/components/schemas/Connectors_config_properties_genai_openai' + discriminator: + propertyName: apiProvider + mapping: + Azure OpenAI: '#/components/schemas/Connectors_config_properties_genai_azure' + OpenAI: '#/components/schemas/Connectors_config_properties_genai_openai' + Connectors_secrets_properties_genai: + title: Connector secrets properties for an OpenAI connector + description: Defines secrets for connectors when type is `.gen-ai`. + type: object + properties: + apiKey: + type: string + description: The OpenAI API key. + Connectors_config_properties_index: + title: Connector request properties for an index connector + required: + - index + description: Defines properties for connectors when type is `.index`. + type: object + properties: + executionTimeField: + description: A field that indicates when the document was indexed. + default: null + type: string + nullable: true + index: + description: The Elasticsearch index to be written to. + type: string + refresh: + description: > + The refresh policy for the write request, which affects when changes + are made visible to search. Refer to the refresh setting for + Elasticsearch document APIs. + default: false + type: boolean + Connectors_config_properties_jira: + title: Connector request properties for a Jira connector + required: + - apiUrl + - projectKey + description: Defines properties for connectors when type is `.jira`. + type: object + properties: + apiUrl: + description: The Jira instance URL. + type: string + projectKey: + description: The Jira project key. + type: string + Connectors_secrets_properties_jira: + title: Connector secrets properties for a Jira connector + required: + - apiToken + - email + description: Defines secrets for connectors when type is `.jira`. + type: object + properties: + apiToken: + description: The Jira API authentication token for HTTP basic authentication. + type: string + email: + description: The account email for HTTP Basic authentication. + type: string + Connectors_config_properties_opsgenie: + title: Connector request properties for an Opsgenie connector + required: + - apiUrl + description: Defines properties for connectors when type is `.opsgenie`. + type: object + properties: + apiUrl: + description: > + The Opsgenie URL. For example, `https://api.opsgenie.com` or + `https://api.eu.opsgenie.com`. If you are using the + `xpack.actions.allowedHosts` setting, add the hostname to the + allowed hosts. + type: string + Connectors_secrets_properties_opsgenie: + title: Connector secrets properties for an Opsgenie connector + required: + - apiKey + description: Defines secrets for connectors when type is `.opsgenie`. + type: object + properties: + apiKey: + description: The Opsgenie API authentication key for HTTP Basic authentication. + type: string + Connectors_config_properties_pagerduty: + title: Connector request properties for a PagerDuty connector + description: Defines properties for connectors when type is `.pagerduty`. + type: object + properties: + apiUrl: + description: The PagerDuty event URL. + type: string + nullable: true + example: https://events.pagerduty.com/v2/enqueue + Connectors_secrets_properties_pagerduty: + title: Connector secrets properties for a PagerDuty connector + description: Defines secrets for connectors when type is `.pagerduty`. + type: object + required: + - routingKey + properties: + routingKey: + description: > + A 32 character PagerDuty Integration Key for an integration on a + service. + type: string + Connectors_config_properties_resilient: + title: Connector request properties for a IBM Resilient connector + required: + - apiUrl + - orgId + description: Defines properties for connectors when type is `.resilient`. + type: object + properties: + apiUrl: + description: The IBM Resilient instance URL. + type: string + orgId: + description: The IBM Resilient organization ID. + type: string + Connectors_secrets_properties_resilient: + title: Connector secrets properties for IBM Resilient connector + required: + - apiKeyId + - apiKeySecret + description: Defines secrets for connectors when type is `.resilient`. + type: object + properties: + apiKeyId: + type: string + description: The authentication key ID for HTTP Basic authentication. + apiKeySecret: + type: string + description: The authentication key secret for HTTP Basic authentication. + Connectors_config_properties_sentinelone: + title: Connector request properties for a SentinelOne connector + required: + - url + description: Defines properties for connectors when type is `.sentinelone`. + type: object + properties: + url: + description: > + The SentinelOne tenant URL. If you are using the + `xpack.actions.allowedHosts` setting, add the hostname to the + allowed hosts. + type: string + Connectors_secrets_properties_sentinelone: + title: Connector secrets properties for a SentinelOne connector + description: Defines secrets for connectors when type is `.sentinelone`. + type: object + required: + - token + properties: + token: + description: The A SentinelOne API token. + type: string + Connectors_config_properties_servicenow: + title: Connector request properties for a ServiceNow ITSM connector + required: + - apiUrl + description: Defines properties for connectors when type is `.servicenow`. + type: object + properties: + apiUrl: + type: string + description: The ServiceNow instance URL. + clientId: + description: > + The client ID assigned to your OAuth application. This property is + required when `isOAuth` is `true`. + type: string + isOAuth: + description: > + The type of authentication to use. The default value is false, which + means basic authentication is used instead of open authorization + (OAuth). + default: false + type: boolean + jwtKeyId: + description: > + The key identifier assigned to the JWT verifier map of your OAuth + application. This property is required when `isOAuth` is `true`. + type: string + userIdentifierValue: + description: > + The identifier to use for OAuth authentication. This identifier + should be the user field you selected when you created an OAuth JWT + API endpoint for external clients in your ServiceNow instance. For + example, if the selected user field is `Email`, the user identifier + should be the user's email address. This property is required when + `isOAuth` is `true`. + type: string + usesTableApi: + description: > + Determines whether the connector uses the Table API or the Import + Set API. This property is supported only for ServiceNow ITSM and + ServiceNow SecOps connectors. NOTE: If this property is set to + `false`, the Elastic application should be installed in ServiceNow. + default: true + type: boolean + Connectors_secrets_properties_servicenow: + title: >- + Connector secrets properties for ServiceNow ITOM, ServiceNow ITSM, and + ServiceNow SecOps connectors + description: >- + Defines secrets for connectors when type is `.servicenow`, + `.servicenow-sir`, or `.servicenow-itom`. + type: object + properties: + clientSecret: + type: string + description: >- + The client secret assigned to your OAuth application. This property + is required when `isOAuth` is `true`. + password: + type: string + description: >- + The password for HTTP basic authentication. This property is + required when `isOAuth` is `false`. + privateKey: + type: string + description: >- + The RSA private key that you created for use in ServiceNow. This + property is required when `isOAuth` is `true`. + privateKeyPassword: + type: string + description: >- + The password for the RSA private key. This property is required when + `isOAuth` is `true` and you set a password on your private key. + username: + type: string + description: >- + The username for HTTP basic authentication. This property is + required when `isOAuth` is `false`. + Connectors_config_properties_servicenow_itom: + title: Connector request properties for a ServiceNow ITSM connector + required: + - apiUrl + description: Defines properties for connectors when type is `.servicenow`. + type: object + properties: + apiUrl: + type: string + description: The ServiceNow instance URL. + clientId: + description: > + The client ID assigned to your OAuth application. This property is + required when `isOAuth` is `true`. + type: string + isOAuth: + description: > + The type of authentication to use. The default value is false, which + means basic authentication is used instead of open authorization + (OAuth). + default: false + type: boolean + jwtKeyId: + description: > + The key identifier assigned to the JWT verifier map of your OAuth + application. This property is required when `isOAuth` is `true`. + type: string + userIdentifierValue: + description: > + The identifier to use for OAuth authentication. This identifier + should be the user field you selected when you created an OAuth JWT + API endpoint for external clients in your ServiceNow instance. For + example, if the selected user field is `Email`, the user identifier + should be the user's email address. This property is required when + `isOAuth` is `true`. + type: string + Connectors_config_properties_slack_api: + title: Connector request properties for a Slack connector + description: Defines properties for connectors when type is `.slack_api`. + type: object + properties: + allowedChannels: + type: array + description: A list of valid Slack channels. + items: + type: object + required: + - id + - name + maxItems: 25 + properties: + id: + type: string + description: The Slack channel ID. + example: C123ABC456 + minLength: 1 + name: + type: string + description: The Slack channel name. + minLength: 1 + Connectors_secrets_properties_slack_api: + title: Connector secrets properties for a Web API Slack connector + description: Defines secrets for connectors when type is `.slack`. + required: + - token + type: object + properties: + token: + type: string + description: Slack bot user OAuth token. + Connectors_secrets_properties_slack_webhook: + title: Connector secrets properties for a Webhook Slack connector + description: Defines secrets for connectors when type is `.slack`. + required: + - webhookUrl + type: object + properties: + webhookUrl: + type: string + description: Slack webhook url. + Connectors_config_properties_swimlane: + title: Connector request properties for a Swimlane connector + required: + - apiUrl + - appId + - connectorType + description: Defines properties for connectors when type is `.swimlane`. + type: object + properties: + apiUrl: + description: The Swimlane instance URL. + type: string + appId: + description: The Swimlane application ID. + type: string + connectorType: + description: >- + The type of connector. Valid values are `all`, `alerts`, and + `cases`. + type: string + enum: + - all + - alerts + - cases + mappings: + title: Connector mappings properties for a Swimlane connector + description: The field mapping. + type: object + properties: + alertIdConfig: + title: Alert identifier mapping + description: Mapping for the alert ID. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + caseIdConfig: + title: Case identifier mapping + description: Mapping for the case ID. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + caseNameConfig: + title: Case name mapping + description: Mapping for the case name. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + commentsConfig: + title: Case comment mapping + description: Mapping for the case comments. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + descriptionConfig: + title: Case description mapping + description: Mapping for the case description. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + ruleNameConfig: + title: Rule name mapping + description: Mapping for the name of the alert's rule. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + severityConfig: + title: Severity mapping + description: Mapping for the severity. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + Connectors_secrets_properties_swimlane: + title: Connector secrets properties for a Swimlane connector + description: Defines secrets for connectors when type is `.swimlane`. + type: object + properties: + apiToken: + description: Swimlane API authentication token. + type: string + Connectors_secrets_properties_teams: + title: Connector secrets properties for a Microsoft Teams connector + description: Defines secrets for connectors when type is `.teams`. + type: object + required: + - webhookUrl + properties: + webhookUrl: + type: string + description: > + The URL of the incoming webhook. If you are using the + `xpack.actions.allowedHosts` setting, add the hostname to the + allowed hosts. + Connectors_config_properties_tines: + title: Connector request properties for a Tines connector + description: Defines properties for connectors when type is `.tines`. + type: object + required: + - url + properties: + url: + description: > + The Tines tenant URL. If you are using the + `xpack.actions.allowedHosts` setting, make sure this hostname is + added to the allowed hosts. + type: string + Connectors_secrets_properties_tines: + title: Connector secrets properties for a Tines connector + description: Defines secrets for connectors when type is `.tines`. + type: object + required: + - email + - token + properties: + email: + description: The email used to sign in to Tines. + type: string + token: + description: The Tines API token. + type: string + Connectors_config_properties_torq: + title: Connector request properties for a Torq connector + description: Defines properties for connectors when type is `.torq`. + type: object + required: + - webhookIntegrationUrl + properties: + webhookIntegrationUrl: + description: The endpoint URL of the Elastic Security integration in Torq. + type: string + Connectors_secrets_properties_torq: + title: Connector secrets properties for a Torq connector + description: Defines secrets for connectors when type is `.torq`. + type: object + required: + - token + properties: + token: + description: The secret of the webhook authentication header. + type: string + Connectors_config_properties_webhook: + title: Connector request properties for a Webhook connector + description: Defines properties for connectors when type is `.webhook`. + type: object + properties: + authType: + type: string + nullable: true + enum: + - webhook-authentication-basic + - webhook-authentication-ssl + description: | + The type of authentication to use: basic, SSL, or none. + ca: + type: string + description: > + A base64 encoded version of the certificate authority file that the + connector can trust to sign and validate certificates. This option + is available for all authentication types. + certType: + type: string + description: > + If the `authType` is `webhook-authentication-ssl`, specifies whether + the certificate authentication data is in a CRT and key file format + or a PFX file format. + enum: + - ssl-crt-key + - ssl-pfx + hasAuth: + type: boolean + description: > + If `true`, a user name and password must be provided for login type + authentication. + headers: + type: object + nullable: true + description: A set of key-value pairs sent as headers with the request. + method: + type: string + default: post + enum: + - post + - put + description: | + The HTTP request method, either `post` or `put`. + url: + type: string + description: > + The request URL. If you are using the `xpack.actions.allowedHosts` + setting, add the hostname to the allowed hosts. + verificationMode: + type: string + enum: + - certificate + - full + - none + default: full + description: > + Controls the verification of certificates. Use `full` to validate + that the certificate has an issue date within the `not_before` and + `not_after` dates, chains to a trusted certificate authority (CA), + and has a hostname or IP address that matches the names within the + certificate. Use `certificate` to validate the certificate and + verify that it is signed by a trusted authority; this option does + not check the certificate hostname. Use `none` to skip certificate + validation. + Connectors_secrets_properties_webhook: + title: Connector secrets properties for a Webhook connector + description: Defines secrets for connectors when type is `.webhook`. + type: object + properties: + crt: + type: string + description: >- + If `authType` is `webhook-authentication-ssl` and `certType` is + `ssl-crt-key`, it is a base64 encoded version of the CRT or CERT + file. + key: + type: string + description: >- + If `authType` is `webhook-authentication-ssl` and `certType` is + `ssl-crt-key`, it is a base64 encoded version of the KEY file. + pfx: + type: string + description: >- + If `authType` is `webhook-authentication-ssl` and `certType` is + `ssl-pfx`, it is a base64 encoded version of the PFX or P12 file. + password: + type: string + description: > + The password for HTTP basic authentication or the passphrase for the + SSL certificate files. If `hasAuth` is set to `true` and `authType` + is `webhook-authentication-basic`, this property is required. + user: + type: string + description: > + The username for HTTP basic authentication. If `hasAuth` is set to + `true` and `authType` is `webhook-authentication-basic`, this + property is required. + Connectors_config_properties_xmatters: + title: Connector request properties for an xMatters connector + description: Defines properties for connectors when type is `.xmatters`. + type: object + properties: + configUrl: + description: > + The request URL for the Elastic Alerts trigger in xMatters. It is + applicable only when `usesBasic` is `true`. + type: string + nullable: true + usesBasic: + description: >- + Specifies whether the connector uses HTTP basic authentication + (`true`) or URL authentication (`false`). + type: boolean + default: true + Connectors_secrets_properties_xmatters: + title: Connector secrets properties for an xMatters connector + description: Defines secrets for connectors when type is `.xmatters`. + type: object + properties: + password: + description: > + A user name for HTTP basic authentication. It is applicable only + when `usesBasic` is `true`. + type: string + secretsUrl: + description: > + The request URL for the Elastic Alerts trigger in xMatters with the + API key included in the URL. It is applicable only when `usesBasic` + is `false`. + type: string + user: + description: > + A password for HTTP basic authentication. It is applicable only when + `usesBasic` is `true`. + type: string + Connectors_create_connector_request: + title: Create connector request body properties + description: The properties vary depending on the connector type. + oneOf: + - $ref: '#/components/schemas/Connectors_create_connector_request_bedrock' + - $ref: '#/components/schemas/Connectors_create_connector_request_gemini' + - $ref: >- + #/components/schemas/Connectors_create_connector_request_cases_webhook + - $ref: '#/components/schemas/Connectors_create_connector_request_d3security' + - $ref: '#/components/schemas/Connectors_create_connector_request_email' + - $ref: '#/components/schemas/Connectors_create_connector_request_genai' + - $ref: '#/components/schemas/Connectors_create_connector_request_index' + - $ref: '#/components/schemas/Connectors_create_connector_request_jira' + - $ref: '#/components/schemas/Connectors_create_connector_request_opsgenie' + - $ref: '#/components/schemas/Connectors_create_connector_request_pagerduty' + - $ref: '#/components/schemas/Connectors_create_connector_request_resilient' + - $ref: '#/components/schemas/Connectors_create_connector_request_sentinelone' + - $ref: '#/components/schemas/Connectors_create_connector_request_serverlog' + - $ref: '#/components/schemas/Connectors_create_connector_request_servicenow' + - $ref: >- + #/components/schemas/Connectors_create_connector_request_servicenow_itom + - $ref: >- + #/components/schemas/Connectors_create_connector_request_servicenow_sir + - $ref: '#/components/schemas/Connectors_create_connector_request_slack_api' + - $ref: >- + #/components/schemas/Connectors_create_connector_request_slack_webhook + - $ref: '#/components/schemas/Connectors_create_connector_request_swimlane' + - $ref: '#/components/schemas/Connectors_create_connector_request_teams' + - $ref: '#/components/schemas/Connectors_create_connector_request_tines' + - $ref: '#/components/schemas/Connectors_create_connector_request_torq' + - $ref: '#/components/schemas/Connectors_create_connector_request_webhook' + - $ref: '#/components/schemas/Connectors_create_connector_request_xmatters' + discriminator: + propertyName: connector_type_id + mapping: + .bedrock: '#/components/schemas/Connectors_create_connector_request_bedrock' + .gemini: '#/components/schemas/Connectors_create_connector_request_gemini' + .cases-webhook: >- + #/components/schemas/Connectors_create_connector_request_cases_webhook + .d3security: '#/components/schemas/Connectors_create_connector_request_d3security' + .email: '#/components/schemas/Connectors_create_connector_request_email' + .gen-ai: '#/components/schemas/Connectors_create_connector_request_genai' + .index: '#/components/schemas/Connectors_create_connector_request_index' + .jira: '#/components/schemas/Connectors_create_connector_request_jira' + .opsgenie: '#/components/schemas/Connectors_create_connector_request_opsgenie' + .pagerduty: '#/components/schemas/Connectors_create_connector_request_pagerduty' + .resilient: '#/components/schemas/Connectors_create_connector_request_resilient' + .sentinelone: '#/components/schemas/Connectors_create_connector_request_sentinelone' + .server-log: '#/components/schemas/Connectors_create_connector_request_serverlog' + .servicenow: '#/components/schemas/Connectors_create_connector_request_servicenow' + .servicenow-itom: >- + #/components/schemas/Connectors_create_connector_request_servicenow_itom + .servicenow-sir: >- + #/components/schemas/Connectors_create_connector_request_servicenow_sir + .slack_api: '#/components/schemas/Connectors_create_connector_request_slack_api' + .slack: >- + #/components/schemas/Connectors_create_connector_request_slack_webhook + .swimlane: '#/components/schemas/Connectors_create_connector_request_swimlane' + .teams: '#/components/schemas/Connectors_create_connector_request_teams' + .tines: '#/components/schemas/Connectors_create_connector_request_tines' + .torq: '#/components/schemas/Connectors_create_connector_request_torq' + .webhook: '#/components/schemas/Connectors_create_connector_request_webhook' + .xmatters: '#/components/schemas/Connectors_create_connector_request_xmatters' + Connectors_connector_response_properties_bedrock: + title: Connector response properties for an Amazon Bedrock connector + type: object + required: + - config + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_bedrock' + connector_type_id: + type: string + description: The type of connector. + enum: + - .bedrock + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + Connectors_connector_response_properties_gemini: + title: Connector response properties for a Google Gemini connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_gemini' + connector_type_id: + type: string + description: The type of connector. + enum: + - .gemini + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_cases_webhook: + title: Connector request properties for a Webhook - Case Management connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_cases_webhook' + connector_type_id: + description: The type of connector. + type: string + enum: + - .cases-webhook + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_d3security: + title: Connector response properties for a D3 Security connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_d3security' + connector_type_id: + type: string + description: The type of connector. + enum: + - .d3security + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_email: + title: Connector response properties for an email connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_email' + connector_type_id: + type: string + description: The type of connector. + enum: + - .email + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_genai: + title: Connector response properties for an OpenAI connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_genai' + connector_type_id: + type: string + description: The type of connector. + enum: + - .gen-ai + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_index: + title: Connector response properties for an index connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_index' + connector_type_id: + type: string + description: The type of connector. + enum: + - .index + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_jira: + title: Connector response properties for a Jira connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_jira' + connector_type_id: + type: string + description: The type of connector. + enum: + - .jira + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_opsgenie: + title: Connector response properties for an Opsgenie connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_opsgenie' + connector_type_id: + type: string + description: The type of connector. + enum: + - .opsgenie + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_pagerduty: + title: Connector response properties for a PagerDuty connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_pagerduty' + connector_type_id: + type: string + description: The type of connector. + enum: + - .pagerduty + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_resilient: + title: Connector response properties for a IBM Resilient connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_resilient' + connector_type_id: + type: string + description: The type of connector. + enum: + - .resilient + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_sentinelone: + title: Connector response properties for a SentinelOne connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_sentinelone' + connector_type_id: + type: string + description: The type of connector. + enum: + - .sentinelone + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_serverlog: + title: Connector response properties for a server log connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + type: object + nullable: true + connector_type_id: + type: string + description: The type of connector. + enum: + - .server-log + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_servicenow: + title: Connector response properties for a ServiceNow ITSM connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_servicenow_itom: + title: Connector response properties for a ServiceNow ITOM connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow_itom' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow-itom + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_servicenow_sir: + title: Connector response properties for a ServiceNow SecOps connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow-sir + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_slack_api: + title: Connector response properties for a Slack connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_slack_api' + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack_api + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_slack_webhook: + title: Connector response properties for a Slack connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_swimlane: + title: Connector response properties for a Swimlane connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_swimlane' + connector_type_id: + type: string + description: The type of connector. + enum: + - .swimlane + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_teams: + title: Connector response properties for a Microsoft Teams connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + type: object + connector_type_id: + type: string + description: The type of connector. + enum: + - .teams + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_tines: + title: Connector response properties for a Tines connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_tines' + connector_type_id: + type: string + description: The type of connector. + enum: + - .tines + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_torq: + title: Connector response properties for a Torq connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_torq' + connector_type_id: + type: string + description: The type of connector. + enum: + - .torq + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_webhook: + title: Connector response properties for a Webhook connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_webhook' + connector_type_id: + type: string + description: The type of connector. + enum: + - .webhook + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_xmatters: + title: Connector response properties for an xMatters connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_xmatters' + connector_type_id: + type: string + description: The type of connector. + enum: + - .xmatters + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_is_deprecated: + type: boolean + description: Indicates whether the connector type is deprecated. + example: false + Connectors_is_missing_secrets: + type: boolean + description: >- + Indicates whether secrets are missing for the connector. Secrets + configuration properties vary depending on the connector type. + example: false + Connectors_is_preconfigured: + type: boolean + description: > + Indicates whether it is a preconfigured connector. If true, the `config` + and `is_missing_secrets` properties are omitted from the response. + example: false + Connectors_is_system_action: + type: boolean + description: Indicates whether the connector is used for system actions. + example: false + Connectors_referenced_by_count: + type: integer + description: > + Indicates the number of saved objects that reference the connector. If + `is_preconfigured` is true, this value is not calculated. This property + is returned only by the get all connectors API. + example: 2 + Connectors_connector_response_properties: + title: Connector response properties + description: The properties vary depending on the connector type. + oneOf: + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_bedrock + - $ref: '#/components/schemas/Connectors_connector_response_properties_gemini' + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_cases_webhook + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_d3security + - $ref: '#/components/schemas/Connectors_connector_response_properties_email' + - $ref: '#/components/schemas/Connectors_connector_response_properties_genai' + - $ref: '#/components/schemas/Connectors_connector_response_properties_index' + - $ref: '#/components/schemas/Connectors_connector_response_properties_jira' + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_opsgenie + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_pagerduty + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_resilient + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_sentinelone + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_serverlog + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_servicenow + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_servicenow_itom + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_servicenow_sir + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_slack_api + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_slack_webhook + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_swimlane + - $ref: '#/components/schemas/Connectors_connector_response_properties_teams' + - $ref: '#/components/schemas/Connectors_connector_response_properties_tines' + - $ref: '#/components/schemas/Connectors_connector_response_properties_torq' + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_webhook + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_xmatters + discriminator: + propertyName: connector_type_id + mapping: + .bedrock: >- + #/components/schemas/Connectors_connector_response_properties_bedrock + .gemini: '#/components/schemas/Connectors_connector_response_properties_gemini' + .cases-webhook: >- + #/components/schemas/Connectors_connector_response_properties_cases_webhook + .d3security: >- + #/components/schemas/Connectors_connector_response_properties_d3security + .email: '#/components/schemas/Connectors_connector_response_properties_email' + .gen-ai: '#/components/schemas/Connectors_connector_response_properties_genai' + .index: '#/components/schemas/Connectors_connector_response_properties_index' + .jira: '#/components/schemas/Connectors_connector_response_properties_jira' + .opsgenie: >- + #/components/schemas/Connectors_connector_response_properties_opsgenie + .pagerduty: >- + #/components/schemas/Connectors_connector_response_properties_pagerduty + .resilient: >- + #/components/schemas/Connectors_connector_response_properties_resilient + .sentinelone: >- + #/components/schemas/Connectors_connector_response_properties_sentinelone + .server-log: >- + #/components/schemas/Connectors_connector_response_properties_serverlog + .servicenow: >- + #/components/schemas/Connectors_connector_response_properties_servicenow + .servicenow-itom: >- + #/components/schemas/Connectors_connector_response_properties_servicenow_itom + .servicenow-sir: >- + #/components/schemas/Connectors_connector_response_properties_servicenow_sir + .slack_api: >- + #/components/schemas/Connectors_connector_response_properties_slack_api + .slack: >- + #/components/schemas/Connectors_connector_response_properties_slack_webhook + .swimlane: >- + #/components/schemas/Connectors_connector_response_properties_swimlane + .teams: '#/components/schemas/Connectors_connector_response_properties_teams' + .tines: '#/components/schemas/Connectors_connector_response_properties_tines' + .torq: '#/components/schemas/Connectors_connector_response_properties_torq' + .webhook: >- + #/components/schemas/Connectors_connector_response_properties_webhook + .xmatters: >- + #/components/schemas/Connectors_connector_response_properties_xmatters + Connectors_update_connector_request_bedrock: + title: Update Amazon Bedrock connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_bedrock' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_bedrock' + Connectors_update_connector_request_gemini: + title: Update Google Gemini connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_gemini' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_gemini' + Connectors_update_connector_request_cases_webhook: + title: Update Webhook - Case Managment connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_cases_webhook' + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_cases_webhook' + Connectors_update_connector_request_d3security: + title: Update D3 Security connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_d3security' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_d3security' + Connectors_update_connector_request_email: + title: Update email connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_email' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_email' + Connectors_update_connector_request_index: + title: Update index connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_index' + name: + type: string + description: The display name for the connector. + Connectors_update_connector_request_jira: + title: Update Jira connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_jira' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_jira' + Connectors_update_connector_request_opsgenie: + title: Update Opsgenie connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_opsgenie' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_opsgenie' + Connectors_update_connector_request_pagerduty: + title: Update PagerDuty connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_pagerduty' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_pagerduty' + Connectors_update_connector_request_resilient: + title: Update IBM Resilient connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_resilient' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_resilient' + Connectors_update_connector_request_sentinelone: + title: Update SentinelOne connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_sentinelone' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_sentinelone' + Connectors_update_connector_request_serverlog: + title: Update server log connector request + type: object + required: + - name + properties: + name: + type: string + description: The display name for the connector. + Connectors_update_connector_request_servicenow: + title: Update ServiceNow ITSM connector or ServiceNow SecOps request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_update_connector_request_servicenow_itom: + title: Create ServiceNow ITOM connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow_itom' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_update_connector_request_slack_api: + title: Update Slack connector request + type: object + required: + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_slack_api' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_slack_api' + Connectors_update_connector_request_slack_webhook: + title: Update Slack connector request + type: object + required: + - name + - secrets + properties: + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_slack_webhook' + Connectors_update_connector_request_swimlane: + title: Update Swimlane connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_swimlane' + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_swimlane' + Connectors_update_connector_request_teams: + title: Update Microsoft Teams connector request + type: object + required: + - name + - secrets + properties: + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_teams' + Connectors_update_connector_request_tines: + title: Update Tines connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_tines' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_tines' + Connectors_update_connector_request_torq: + title: Update Torq connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_torq' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_torq' + Connectors_update_connector_request_webhook: + title: Update Webhook connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_webhook' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_webhook' + Connectors_update_connector_request_xmatters: + title: Update xMatters connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_xmatters' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_xmatters' + Connectors_update_connector_request: + title: Update connector request body properties + description: The properties vary depending on the connector type. + oneOf: + - $ref: '#/components/schemas/Connectors_update_connector_request_bedrock' + - $ref: '#/components/schemas/Connectors_update_connector_request_gemini' + - $ref: >- + #/components/schemas/Connectors_update_connector_request_cases_webhook + - $ref: '#/components/schemas/Connectors_update_connector_request_d3security' + - $ref: '#/components/schemas/Connectors_update_connector_request_email' + - $ref: '#/components/schemas/Connectors_create_connector_request_genai' + - $ref: '#/components/schemas/Connectors_update_connector_request_index' + - $ref: '#/components/schemas/Connectors_update_connector_request_jira' + - $ref: '#/components/schemas/Connectors_update_connector_request_opsgenie' + - $ref: '#/components/schemas/Connectors_update_connector_request_pagerduty' + - $ref: '#/components/schemas/Connectors_update_connector_request_resilient' + - $ref: '#/components/schemas/Connectors_update_connector_request_sentinelone' + - $ref: '#/components/schemas/Connectors_update_connector_request_serverlog' + - $ref: '#/components/schemas/Connectors_update_connector_request_servicenow' + - $ref: >- + #/components/schemas/Connectors_update_connector_request_servicenow_itom + - $ref: '#/components/schemas/Connectors_update_connector_request_slack_api' + - $ref: >- + #/components/schemas/Connectors_update_connector_request_slack_webhook + - $ref: '#/components/schemas/Connectors_update_connector_request_swimlane' + - $ref: '#/components/schemas/Connectors_update_connector_request_teams' + - $ref: '#/components/schemas/Connectors_update_connector_request_tines' + - $ref: '#/components/schemas/Connectors_update_connector_request_torq' + - $ref: '#/components/schemas/Connectors_update_connector_request_webhook' + - $ref: '#/components/schemas/Connectors_update_connector_request_xmatters' + Connectors_features: + type: string + description: | + The feature that uses the connector. + enum: + - alerting + - cases + - generativeAIForSecurity + - generativeAIForObservability + - generativeAIForSearchPlayground + - siem + - uptime + Connectors_connector_types: + title: Connector types + type: string + description: >- + The type of connector. For example, `.email`, `.index`, `.jira`, + `.opsgenie`, or `.server-log`. + enum: + - .bedrock + - .gemini + - .cases-webhook + - .d3security + - .email + - .gen-ai + - .index + - .jira + - .opsgenie + - .pagerduty + - .resilient + - .sentinelone + - .servicenow + - .servicenow-itom + - .servicenow-sir + - .server-log + - .slack + - .slack_api + - .swimlane + - .teams + - .tines + - .torq + - .webhook + - .xmatters + example: .server-log + Data_views_400_response: + title: Bad request + type: object + required: + - statusCode + - error + - message + properties: + statusCode: + type: number + example: 400 + error: + type: string + example: Bad Request + message: + type: string + Data_views_allownoindex: + type: boolean + description: Allows the data view saved object to exist before the data is available. + Data_views_fieldattrs: + type: object + description: A map of field attributes by field name. + Data_views_fieldformats: + type: object + description: A map of field formats by field name. + Data_views_namespaces: + type: array + description: >- + An array of space identifiers for sharing the data view between multiple + spaces. + items: + type: string + default: default + Data_views_runtimefieldmap: + type: object + description: A map of runtime field definitions by field name. + Data_views_sourcefilters: + type: array + description: The array of field names you want to filter out in Discover. + items: + type: object + required: + - value + properties: + value: + type: string + Data_views_timefieldname: + type: string + description: The timestamp field name, which you use for time-based data views. + Data_views_title: + type: string + description: >- + Comma-separated list of data streams, indices, and aliases that you want + to search. Supports wildcards (`*`). + Data_views_type: + type: string + description: When set to `rollup`, identifies the rollup data views. + Data_views_typemeta: + type: object + description: >- + When you use rollup indices, contains the field list for the rollup data + view API endpoints. + Data_views_create_data_view_request_object: + title: Create data view request + type: object + required: + - data_view + properties: + data_view: + type: object + required: + - title + description: The data view object. + properties: + allowNoIndex: + $ref: '#/components/schemas/Data_views_allownoindex' + fieldAttrs: + $ref: '#/components/schemas/Data_views_fieldattrs' + fieldFormats: + $ref: '#/components/schemas/Data_views_fieldformats' + fields: + type: object + id: + type: string + name: + type: string + description: The data view name. + namespaces: + $ref: '#/components/schemas/Data_views_namespaces' + runtimeFieldMap: + $ref: '#/components/schemas/Data_views_runtimefieldmap' + sourceFilters: + $ref: '#/components/schemas/Data_views_sourcefilters' + timeFieldName: + $ref: '#/components/schemas/Data_views_timefieldname' + title: + $ref: '#/components/schemas/Data_views_title' + type: + $ref: '#/components/schemas/Data_views_type' + typeMeta: + $ref: '#/components/schemas/Data_views_typemeta' + version: + type: string + override: + type: boolean + description: >- + Override an existing data view if a data view with the provided + title already exists. + default: false + Data_views_data_view_response_object: + title: Data view response properties + type: object + properties: + data_view: + type: object + properties: + allowNoIndex: + $ref: '#/components/schemas/Data_views_allownoindex' + fieldAttrs: + $ref: '#/components/schemas/Data_views_fieldattrs' + fieldFormats: + $ref: '#/components/schemas/Data_views_fieldformats' + fields: + type: object + id: + type: string + example: ff959d40-b880-11e8-a6d9-e546fe2bba5f + name: + type: string + description: The data view name. + namespaces: + $ref: '#/components/schemas/Data_views_namespaces' + runtimeFieldMap: + $ref: '#/components/schemas/Data_views_runtimefieldmap' + sourceFilters: + $ref: '#/components/schemas/Data_views_sourcefilters' + timeFieldName: + $ref: '#/components/schemas/Data_views_timefieldname' + title: + $ref: '#/components/schemas/Data_views_title' + typeMeta: + $ref: '#/components/schemas/Data_views_typemeta' + version: + type: string + example: WzQ2LDJd + Data_views_404_response: + type: object + properties: + error: + type: string + example: Not Found + enum: + - Not Found + message: + type: string + example: >- + Saved object [index-pattern/caaad6d0-920c-11ed-b36a-874bd1548a00] + not found + statusCode: + type: integer + example: 404 + enum: + - 404 + Data_views_update_data_view_request_object: + title: Update data view request + type: object + required: + - data_view + properties: + data_view: + type: object + description: > + The data view properties you want to update. Only the specified + properties are updated in the data view. Unspecified fields stay as + they are persisted. + properties: + allowNoIndex: + $ref: '#/components/schemas/Data_views_allownoindex' + fieldFormats: + $ref: '#/components/schemas/Data_views_fieldformats' + fields: + type: object + name: + type: string + runtimeFieldMap: + $ref: '#/components/schemas/Data_views_runtimefieldmap' + sourceFilters: + $ref: '#/components/schemas/Data_views_sourcefilters' + timeFieldName: + $ref: '#/components/schemas/Data_views_timefieldname' + title: + $ref: '#/components/schemas/Data_views_title' + type: + $ref: '#/components/schemas/Data_views_type' + typeMeta: + $ref: '#/components/schemas/Data_views_typemeta' + refresh_fields: + type: boolean + description: Reloads the data view fields after the data view is updated. + default: false + Machine_learning_APIs_mlSyncResponseSuccess: + type: boolean + description: The success or failure of the synchronization. + Machine_learning_APIs_mlSyncResponseAnomalyDetectors: + type: object + title: Sync API response for anomaly detection jobs + description: >- + The sync machine learning saved objects API response contains this + object when there are anomaly detection jobs affected by the + synchronization. There is an object for each relevant job, which + contains the synchronization status. + properties: + success: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseSuccess' + Machine_learning_APIs_mlSyncResponseDatafeeds: + type: object + title: Sync API response for datafeeds + description: >- + The sync machine learning saved objects API response contains this + object when there are datafeeds affected by the synchronization. There + is an object for each relevant datafeed, which contains the + synchronization status. + properties: + success: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseSuccess' + Machine_learning_APIs_mlSyncResponseDataFrameAnalytics: + type: object + title: Sync API response for data frame analytics jobs + description: >- + The sync machine learning saved objects API response contains this + object when there are data frame analytics jobs affected by the + synchronization. There is an object for each relevant job, which + contains the synchronization status. + properties: + success: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseSuccess' + Machine_learning_APIs_mlSyncResponseSavedObjectsCreated: + type: object + title: Sync API response for created saved objects + description: >- + If saved objects are missing for machine learning jobs or trained + models, they are created when you run the sync machine learning saved + objects API. + properties: + anomaly-detector: + type: object + description: >- + If saved objects are missing for anomaly detection jobs, they are + created. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseAnomalyDetectors + data-frame-analytics: + type: object + description: >- + If saved objects are missing for data frame analytics jobs, they are + created. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseDataFrameAnalytics + trained-model: + type: object + description: If saved objects are missing for trained models, they are created. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseTrainedModels + Machine_learning_APIs_mlSyncResponseSavedObjectsDeleted: + type: object + title: Sync API response for deleted saved objects + description: >- + If saved objects exist for machine learning jobs or trained models that + no longer exist, they are deleted when you run the sync machine learning + saved objects API. + properties: + anomaly-detector: + type: object + description: >- + If there are saved objects exist for nonexistent anomaly detection + jobs, they are deleted. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseAnomalyDetectors + data-frame-analytics: + type: object + description: >- + If there are saved objects exist for nonexistent data frame + analytics jobs, they are deleted. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseDataFrameAnalytics + trained-model: + type: object + description: >- + If there are saved objects exist for nonexistent trained models, + they are deleted. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseTrainedModels + Machine_learning_APIs_mlSyncResponseTrainedModels: + type: object + title: Sync API response for trained models + description: >- + The sync machine learning saved objects API response contains this + object when there are trained models affected by the synchronization. + There is an object for each relevant trained model, which contains the + synchronization status. + properties: + success: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseSuccess' + Machine_learning_APIs_mlSync200Response: + type: object + title: Successful sync API response + properties: + datafeedsAdded: + type: object + description: >- + If a saved object for an anomaly detection job is missing a datafeed + identifier, it is added when you run the sync machine learning saved + objects API. + additionalProperties: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseDatafeeds' + datafeedsRemoved: + type: object + description: >- + If a saved object for an anomaly detection job references a datafeed + that no longer exists, it is deleted when you run the sync machine + learning saved objects API. + additionalProperties: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseDatafeeds' + savedObjectsCreated: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseSavedObjectsCreated + savedObjectsDeleted: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseSavedObjectsDeleted + Machine_learning_APIs_mlSync4xxResponse: + type: object + title: Unsuccessful sync API response + properties: + error: + type: string + example: Unauthorized + message: + type: string + statusCode: + type: integer + example: 401 + Serverless_saved_objects_400_response: + title: Bad request + type: object + required: + - error + - message + - statusCode + properties: + error: + type: string + enum: + - Bad Request + message: + type: string + statusCode: + type: integer + enum: + - 400 + Serverless_saved_objects_export_objects_request: + type: object + properties: + excludeExportDetails: + description: Do not add export details entry at the end of the stream. + type: boolean + default: false + includeReferencesDeep: + description: Includes all of the referenced objects in the exported objects. + type: boolean + objects: + description: A list of objects to export. + type: array + items: + type: object + type: + description: >- + The saved object types to include in the export. Use `*` to export + all the types. + oneOf: + - type: string + - type: array + items: + type: string + Serverless_saved_objects_import_objects_request: + type: object + properties: + file: + description: > + A file exported using the export API. NOTE: The + `savedObjects.maxImportExportSize` configuration setting limits the + number of saved objects which may be included in this file. + Similarly, the `savedObjects.maxImportPayloadBytes` setting limits + the overall size of the file that can be imported. + Serverless_saved_objects_200_import_objects_response: + type: object + properties: + success: + type: boolean + description: > + Indicates when the import was successfully completed. When set to + false, some objects may not have been created. For additional + information, refer to the `errors` and `successResults` properties. + successCount: + type: integer + description: Indicates the number of successfully imported records. + errors: + type: array + items: + type: object + description: > + Indicates the import was unsuccessful and specifies the objects that + failed to import. + + + NOTE: One object may result in multiple errors, which requires + separate steps to resolve. For instance, a `missing_references` + error and conflict error. + successResults: + type: array + items: + type: object + description: > + Indicates the objects that are successfully imported, with any + metadata if applicable. + + + NOTE: Objects are created only when all resolvable errors are + addressed, including conflicts and missing references. If objects + are created as new copies, each entry in the `successResults` array + includes a `destinationId` attribute. + examples: + Connectors_create_email_connector_request: + summary: Create an email connector. + value: + name: email-connector-1 + connector_type_id: .email + config: + from: tester@example.com + hasAuth: true + host: https://example.com + port: 1025 + secure: false + service: other + secrets: + user: username + password: password + Connectors_create_index_connector_request: + summary: Create an index connector. + value: + name: my-connector + connector_type_id: .index + config: + index: test-index + Connectors_create_webhook_connector_request: + summary: Create a webhook connector with SSL authentication. + value: + name: my-webhook-connector + connector_type_id: .webhook + config: + method: post + url: https://example.com + authType: webhook-authentication-ssl + certType: ssl-crt-key + secrets: + crt: QmFnIEF0dH... + key: LS0tLS1CRUdJ... + password: my-passphrase + Connectors_create_xmatters_connector_request: + summary: Create an xMatters connector with URL authentication. + value: + name: my-xmatters-connector + connector_type_id: .xmatters + config: + usesBasic: false + secrets: + secretsUrl: https://example.com?apiKey=xxxxx + Connectors_create_email_connector_response: + summary: A new email connector. + value: + id: 90a82c60-478f-11ee-a343-f98a117c727f + connector_type_id: .email + name: email-connector-1 + config: + from: tester@example.com + service: other + host: https://example.com + port: 1025 + secure: false + hasAuth: true + tenantId: null + clientId: null + oauthTokenUrl: null + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_create_index_connector_response: + summary: A new index connector. + value: + id: c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad + connector_type_id: .index + name: my-connector + config: + index: test-index + refresh: false + executionTimeField: null + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_create_webhook_connector_response: + summary: A new webhook connector. + value: + id: 900eb010-3b9d-11ee-a642-8ffbb94e38bd + name: my-webhook-connector + config: + method: post + url: https://example.com + authType: webhook-authentication-ssl + certType: ssl-crt-key + verificationMode: full + headers: null + hasAuth: true + connector_type_id: .webhook + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_create_xmatters_connector_response: + summary: A new xMatters connector. + value: + id: 4d2d8da0-4d1f-11ee-9367-577408be4681 + name: my-xmatters-connector + config: + usesBasic: false + configUrl: null + connector_type_id: .xmatters + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_get_connector_response: + summary: Get connector details. + value: + id: df770e30-8b8b-11ed-a780-3b746c987a81 + name: my_server_log_connector + config: {} + connector_type_id: .server-log + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_update_index_connector_request: + summary: Update an index connector. + value: + name: updated-connector + config: + index: updated-index + Connectors_get_connectors_response: + summary: A list of connectors + value: + - id: preconfigured-email-connector + name: my-preconfigured-email-notification + connector_type_id: .email + is_preconfigured: true + is_deprecated: false + referenced_by_count: 0 + is_system_action: false + - id: e07d0c80-8b8b-11ed-a780-3b746c987a81 + name: my-index-connector + config: + index: test-index + refresh: false + executionTimeField: null + connector_type_id: .index + is_preconfigured: false + is_deprecated: false + referenced_by_count: 2 + is_missing_secrets: false + is_system_action: false + Connectors_get_connector_types_generativeai_response: + summary: A list of connector types for the `generativeAI` feature. + value: + - id: .gen-ai + name: OpenAI + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: enterprise + supported_feature_ids: + - generativeAIForSecurity + - generativeAIForObservability + - generativeAIForSearchPlayground + is_system_action_type: false + - id: .bedrock + name: AWS Bedrock + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: enterprise + supported_feature_ids: + - generativeAIForSecurity + - generativeAIForObservability + - generativeAIForSearchPlayground + is_system_action_type: false + - id: .gemini + name: Google Gemini + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: enterprise + supported_feature_ids: + - generativeAIForSecurity + is_system_action_type: false + Data_views_get_data_views_response: + summary: The get all data views API returns a list of data views. + value: + data_view: + - id: ff959d40-b880-11e8-a6d9-e546fe2bba5f + namespaces: + - default + title: kibana_sample_data_ecommerce + typeMeta: {} + name: Kibana Sample Data eCommerce + - id: d3d7af60-4c81-11e8-b3d7-01146121b73d + namespaces: + - default + title: kibana_sample_data_flights + name: Kibana Sample Data Flights + - id: 90943e30-9a47-11e8-b64d-95841ca0b247 + namespaces: + - default + title: kibana_sample_data_logs + name: Kibana Sample Data Logs + Data_views_create_data_view_request: + summary: Create a data view with runtime fields. + value: + data_view: + title: logstash-* + name: My Logstash data view + runtimeFieldMap: + runtime_shape_name: + type: keyword + script: + source: emit(doc['shape_name'].value) + Data_views_get_data_view_response: + summary: >- + The get data view API returns a JSON object that contains information + about the data view. + value: + data_view: + id: ff959d40-b880-11e8-a6d9-e546fe2bba5f + version: WzUsMV0= + title: kibana_sample_data_ecommerce + timeFieldName: order_date + sourceFilters: [] + fields: + _id: + count: 0 + name: _id + type: string + esTypes: + - _id + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + _index: + count: 0 + name: _index + type: string + esTypes: + - _index + scripted: false + searchable: true + aggregatable: true + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + _score: + count: 0 + name: _score + type: number + scripted: false + searchable: false + aggregatable: false + readFromDocValues: false + format: + id: number + shortDotsEnable: false + isMapped: true + _source: + count: 0 + name: _source + type: _source + esTypes: + - _source + scripted: false + searchable: false + aggregatable: false + readFromDocValues: false + format: + id: _source + shortDotsEnable: false + isMapped: true + category: + count: 0 + name: category + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + category.keyword: + count: 0 + name: category.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: category + format: + id: string + shortDotsEnable: false + isMapped: true + currency: + count: 0 + name: currency + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + customer_birth_date: + count: 0 + name: customer_birth_date + type: date + esTypes: + - date + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: date + shortDotsEnable: false + isMapped: true + customer_first_name: + count: 0 + name: customer_first_name + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + customer_first_name.keyword: + count: 0 + name: customer_first_name.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: customer_first_name + format: + id: string + shortDotsEnable: false + isMapped: true + customer_full_name: + count: 0 + name: customer_full_name + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + customer_full_name.keyword: + count: 0 + name: customer_full_name.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: customer_full_name + format: + id: string + shortDotsEnable: false + isMapped: true + customer_gender: + count: 0 + name: customer_gender + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + customer_id: + count: 0 + name: customer_id + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + customer_last_name: + count: 0 + name: customer_last_name + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + customer_last_name.keyword: + count: 0 + name: customer_last_name.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: customer_last_name + format: + id: string + shortDotsEnable: false + isMapped: true + customer_phone: + count: 0 + name: customer_phone + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + day_of_week: + count: 0 + name: day_of_week + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + day_of_week_i: + count: 0 + name: day_of_week_i + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + email: + count: 0 + name: email + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + event.dataset: + count: 0 + name: event.dataset + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + geoip.city_name: + count: 0 + name: geoip.city_name + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + geoip.continent_name: + count: 0 + name: geoip.continent_name + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + geoip.country_iso_code: + count: 0 + name: geoip.country_iso_code + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + geoip.location: + count: 0 + name: geoip.location + type: geo_point + esTypes: + - geo_point + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: geo_point + params: + transform: wkt + shortDotsEnable: false + isMapped: true + geoip.region_name: + count: 0 + name: geoip.region_name + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + manufacturer: + count: 0 + name: manufacturer + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + manufacturer.keyword: + count: 0 + name: manufacturer.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: manufacturer + format: + id: string + shortDotsEnable: false + isMapped: true + order_date: + count: 0 + name: order_date + type: date + esTypes: + - date + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: date + shortDotsEnable: false + isMapped: true + order_id: + count: 0 + name: order_id + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + products._id: + count: 0 + name: products._id + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + products._id.keyword: + count: 0 + name: products._id.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: products._id + format: + id: string + shortDotsEnable: false + isMapped: true + products.base_price: + count: 0 + name: products.base_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.base_unit_price: + count: 0 + name: products.base_unit_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.category: + count: 0 + name: products.category + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + products.category.keyword: + count: 0 + name: products.category.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: products.category + format: + id: string + shortDotsEnable: false + isMapped: true + products.created_on: + count: 0 + name: products.created_on + type: date + esTypes: + - date + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: date + shortDotsEnable: false + isMapped: true + products.discount_amount: + count: 0 + name: products.discount_amount + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.discount_percentage: + count: 0 + name: products.discount_percentage + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.manufacturer: + count: 1 + name: products.manufacturer + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + products.manufacturer.keyword: + count: 0 + name: products.manufacturer.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: products.manufacturer + format: + id: string + shortDotsEnable: false + isMapped: true + products.min_price: + count: 0 + name: products.min_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.price: + count: 1 + name: products.price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.product_id: + count: 0 + name: products.product_id + type: number + esTypes: + - long + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.product_name: + count: 1 + name: products.product_name + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + products.product_name.keyword: + count: 0 + name: products.product_name.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: products.product_name + format: + id: string + shortDotsEnable: false + isMapped: true + products.quantity: + count: 0 + name: products.quantity + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.sku: + count: 0 + name: products.sku + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + products.tax_amount: + count: 0 + name: products.tax_amount + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.taxful_price: + count: 0 + name: products.taxful_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.taxless_price: + count: 0 + name: products.taxless_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.unit_discount_amount: + count: 0 + name: products.unit_discount_amount + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + sku: + count: 0 + name: sku + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + taxful_total_price: + count: 0 + name: taxful_total_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.[00] + shortDotsEnable: false + isMapped: true + taxless_total_price: + count: 0 + name: taxless_total_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + total_quantity: + count: 1 + name: total_quantity + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + total_unique_products: + count: 0 + name: total_unique_products + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + type: + count: 0 + name: type + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + user: + count: 0 + name: user + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + typeMeta: {} + fieldFormats: + taxful_total_price: + id: number + params: + pattern: $0,0.[00] + products.price: + id: number + params: + pattern: $0,0.00 + taxless_total_price: + id: number + params: + pattern: $0,0.00 + products.taxless_price: + id: number + params: + pattern: $0,0.00 + products.taxful_price: + id: number + params: + pattern: $0,0.00 + products.min_price: + id: number + params: + pattern: $0,0.00 + products.base_unit_price: + id: number + params: + pattern: $0,0.00 + products.base_price: + id: number + params: + pattern: $0,0.00 + runtimeFieldMap: {} + fieldAttrs: + products.manufacturer: + count: 1 + products.price: + count: 1 + products.product_name: + count: 1 + total_quantity: + count: 1 + allowNoIndex: false + name: Kibana Sample Data eCommerce + namespaces: + - default + Data_views_update_data_view_request: + summary: Update some properties for a data view. + value: + data_view: + title: kibana_sample_data_ecommerce + timeFieldName: order_date + allowNoIndex: false + name: Kibana Sample Data eCommerce + refresh_fields: true + Data_views_get_default_data_view_response: + summary: The get default data view API returns the default data view identifier. + value: + data_view_id: ff959d40-b880-11e8-a6d9-e546fe2bba5f + Data_views_set_default_data_view_request: + summary: Set the default data view identifier. + value: + data_view_id: ff959d40-b880-11e8-a6d9-e546fe2bba5f + force: true + Data_views_update_field_metadata_request: + summary: Set popularity count for field foo. + value: + fields: + foo: + count: 123 + Data_views_create_runtime_field_request: + summary: Create a runtime field. + value: + name: runtimeFoo + runtimeField: + type: long + script: + source: emit(doc["foo"].value) + Data_views_get_runtime_field_response: + summary: >- + The get runtime field API returns a JSON object that contains + information about the runtime field (`hour_of_day`) and the data view + (`d3d7af60-4c81-11e8-b3d7-01146121b73d`). + value: + fields: + - count: 0 + name: hour_of_day + type: number + esTypes: + - long + scripted: false + searchable: true + aggregatable: true + readFromDocValues: false + shortDotsEnable: false + runtimeField: + type: long + script: + source: emit(doc['timestamp'].value.getHour()); + data_view: + id: d3d7af60-4c81-11e8-b3d7-01146121b73d + version: WzM2LDJd + title: kibana_sample_data_flights + timeFieldName: timestamp + sourceFilters: [] + fields: + hour_of_day: + count: 0 + name: hour_of_day + type: number + esTypes: + - long + scripted: false + searchable: true + aggregatable: true + readFromDocValues: false + format: + id: number + params: + pattern: '00' + shortDotsEnable: false + runtimeField: + type: long + script: + source: emit(doc['timestamp'].value.getHour()); + AvgTicketPrice: + count: 0 + name: AvgTicketPrice + type: number + esTypes: + - float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.[00] + shortDotsEnable: false + isMapped: true + Cancelled: + count: 0 + name: Cancelled + type: boolean + esTypes: + - boolean + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: boolean + shortDotsEnable: false + isMapped: true + Carrier: + count: 0 + name: Carrier + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + Dest: + count: 0 + name: Dest + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestAirportID: + count: 0 + name: DestAirportID + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestCityName: + count: 0 + name: DestCityName + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestCountry: + count: 0 + name: DestCountry + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestLocation: + count: 0 + name: DestLocation + type: geo_point + esTypes: + - geo_point + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: geo_point + params: + transform: wkt + shortDotsEnable: false + isMapped: true + DestRegion: + count: 0 + name: DestRegion + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestWeather: + count: 0 + name: DestWeather + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DistanceKilometers: + count: 0 + name: DistanceKilometers + type: number + esTypes: + - float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + DistanceMiles: + count: 0 + name: DistanceMiles + type: number + esTypes: + - float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + FlightDelay: + count: 0 + name: FlightDelay + type: boolean + esTypes: + - boolean + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: boolean + shortDotsEnable: false + isMapped: true + FlightDelayMin: + count: 0 + name: FlightDelayMin + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + FlightDelayType: + count: 0 + name: FlightDelayType + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + FlightNum: + count: 0 + name: FlightNum + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + FlightTimeHour: + count: 0 + name: FlightTimeHour + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + FlightTimeMin: + count: 0 + name: FlightTimeMin + type: number + esTypes: + - float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + Origin: + count: 0 + name: Origin + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginAirportID: + count: 0 + name: OriginAirportID + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginCityName: + count: 0 + name: OriginCityName + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginCountry: + count: 0 + name: OriginCountry + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginLocation: + count: 0 + name: OriginLocation + type: geo_point + esTypes: + - geo_point + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: geo_point + params: + transform: wkt + shortDotsEnable: false + isMapped: true + OriginRegion: + count: 0 + name: OriginRegion + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginWeather: + count: 0 + name: OriginWeather + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + _id: + count: 0 + name: _id + type: string + esTypes: + - _id + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + _index: + count: 0 + name: _index + type: string + esTypes: + - _index + scripted: false + searchable: true + aggregatable: true + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + _score: + count: 0 + name: _score + type: number + scripted: false + searchable: false + aggregatable: false + readFromDocValues: false + format: + id: number + shortDotsEnable: false + isMapped: true + _source: + count: 0 + name: _source + type: _source + esTypes: + - _source + scripted: false + searchable: false + aggregatable: false + readFromDocValues: false + format: + id: _source + shortDotsEnable: false + isMapped: true + dayOfWeek: + count: 0 + name: dayOfWeek + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + timestamp: + count: 0 + name: timestamp + type: date + esTypes: + - date + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: date + shortDotsEnable: false + isMapped: true + fieldFormats: + hour_of_day: + id: number + params: + pattern: '00' + AvgTicketPrice: + id: number + params: + pattern: $0,0.[00] + runtimeFieldMap: + hour_of_day: + type: long + script: + source: emit(doc['timestamp'].value.getHour()); + fieldAttrs: {} + allowNoIndex: false + name: Kibana Sample Data Flights + Data_views_update_runtime_field_request: + summary: Update an existing runtime field on a data view. + value: + runtimeField: + script: + source: emit(doc["bar"].value) + Machine_learning_APIs_mlSyncExample: + summary: Two anomaly detection jobs required synchronization in this example. + value: + savedObjectsCreated: + anomaly-detector: + myjob1: + success: true + myjob2: + success: true + savedObjectsDeleted: {} + datafeedsAdded: {} + datafeedsRemoved: {} + Serverless_saved_objects_export_objects_request: + summary: Export a specific saved object. + value: + objects: + - type: map + id: de71f4f0-1902-11e9-919b-ffe5949a18d2 + includeReferencesDeep: false + excludeExportDetails: true + Serverless_saved_objects_export_objects_response: + summary: >- + The export objects API response contains a JSON record for each exported + object. + value: + attributes: + description: '' + layerListJSON: >- + [{"id":"0hmz5","alpha":1,"sourceDescriptor":{"type":"EMS_TMS","isAutoSelect":true,"lightModeDefault":"road_map_desaturated"},"visible":true,"style":{},"type":"EMS_VECTOR_TILE","minZoom":0,"maxZoom":24},{"id":"edh66","label":"Total + Requests by + Destination","minZoom":0,"maxZoom":24,"alpha":0.5,"sourceDescriptor":{"type":"EMS_FILE","id":"world_countries","tooltipProperties":["name","iso2"]},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"__kbnjoin__count__673ff994-fc75-4c67-909b-69fcb0e1060e","origin":"join"},"color":"Greys","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"STATIC","options":{"size":10}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"GEOJSON_VECTOR","joins":[{"leftField":"iso2","right":{"type":"ES_TERM_SOURCE","id":"673ff994-fc75-4c67-909b-69fcb0e1060e","indexPatternTitle":"kibana_sample_data_logs","term":"geo.dest","indexPatternRefName":"layer_1_join_0_index_pattern","metrics":[{"type":"count","label":"web + logs + count"}],"applyGlobalQuery":true}}]},{"id":"gaxya","label":"Actual + Requests","minZoom":9,"maxZoom":24,"alpha":1,"sourceDescriptor":{"id":"b7486535-171b-4d3b-bb2e-33c1a0a2854c","type":"ES_SEARCH","geoField":"geo.coordinates","limit":2048,"filterByMapBounds":true,"tooltipProperties":["clientip","timestamp","host","request","response","machine.os","agent","bytes"],"indexPatternRefName":"layer_2_source_index_pattern","applyGlobalQuery":true,"scalingType":"LIMIT"},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"STATIC","options":{"color":"#2200ff"}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":2}},"iconSize":{"type":"DYNAMIC","options":{"field":{"name":"bytes","origin":"source"},"minSize":1,"maxSize":23,"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"GEOJSON_VECTOR"},{"id":"tfi3f","label":"Total + Requests and + Bytes","minZoom":0,"maxZoom":9,"alpha":1,"sourceDescriptor":{"type":"ES_GEO_GRID","resolution":"COARSE","id":"8aaa65b5-a4e9-448b-9560-c98cb1c5ac5b","geoField":"geo.coordinates","requestType":"point","metrics":[{"type":"count","label":"web + logs + count"},{"type":"sum","field":"bytes"}],"indexPatternRefName":"layer_3_source_index_pattern","applyGlobalQuery":true},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"doc_count","origin":"source"},"color":"Blues","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#cccccc"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"DYNAMIC","options":{"field":{"name":"sum_of_bytes","origin":"source"},"minSize":7,"maxSize":25,"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"labelText":{"type":"DYNAMIC","options":{"field":{"name":"doc_count","origin":"source"},"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"labelSize":{"type":"DYNAMIC","options":{"field":{"name":"doc_count","origin":"source"},"minSize":12,"maxSize":24,"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"GEOJSON_VECTOR"}] + mapStateJSON: >- + {"zoom":3.64,"center":{"lon":-88.92107,"lat":42.16337},"timeFilters":{"from":"now-7d","to":"now"},"refreshConfig":{"isPaused":true,"interval":0},"query":{"language":"kuery","query":""},"settings":{"autoFitToDataBounds":false}} + title: '[Logs] Total Requests and Bytes' + uiStateJSON: '{"isDarkMode":false}' + coreMigrationVersion: 8.8.0 + created_at: '2023-08-23T20:03:32.204Z' + id: de71f4f0-1902-11e9-919b-ffe5949a18d2 + managed: false + references: + - id: 90943e30-9a47-11e8-b64d-95841ca0b247 + name: layer_1_join_0_index_pattern + type: index-pattern + - id: 90943e30-9a47-11e8-b64d-95841ca0b247 + name: layer_2_source_index_pattern + type: index-pattern + - id: 90943e30-9a47-11e8-b64d-95841ca0b247 + name: layer_3_source_index_pattern + type: index-pattern + type: map + typeMigrationVersion: 8.4.0 + updated_at: '2023-08-23T20:03:32.204Z' + version: WzEzLDFd + Serverless_saved_objects_import_objects_request: + value: + file: file.ndjson + Serverless_saved_objects_import_objects_response: + summary: >- + The import objects API response indicates a successful import and the + objects are created. Since these objects are created as new copies, each + entry in the successResults array includes a destinationId attribute. + value: + successCount: 1 + success: true + successResults: + - type: index-pattern + id: 90943e30-9a47-11e8-b64d-95841ca0b247 + meta: + title: Kibana Sample Data Logs + icon: indexPatternApp + managed: false + destinationId: 82d2760c-468f-49cf-83aa-b9a35b6a8943 + responses: + Connectors_401: + description: Authorization information is missing or invalid. + content: + application/json: + schema: + type: object + title: Unauthorized response + properties: + error: + type: string + example: Unauthorized + enum: + - Unauthorized + message: + type: string + statusCode: + type: integer + example: 401 + enum: + - 401 + Connectors_404: + description: Object is not found. + content: + application/json: + schema: + type: object + title: Not found response + properties: + error: + type: string + example: Not Found + enum: + - Not Found + message: + type: string + example: >- + Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not + found + statusCode: + type: integer + example: 404 + enum: + - 404 +x-tagGroups: + - name: APM UI + tags: + - APM agent keys + - APM annotations + - name: Connectors + tags: + - connectors + - name: Data views + tags: + - data views + - name: Machine learning APIs + tags: + - ml + - name: Serverless saved objects + tags: + - saved objects diff --git a/oas_docs/makefile b/oas_docs/makefile new file mode 100644 index 00000000000000..805da0b6218a75 --- /dev/null +++ b/oas_docs/makefile @@ -0,0 +1,29 @@ +# ELASTICSEARCH CONFIDENTIAL +# __________________ +# +# Copyright Elasticsearch B.V. All rights reserved. +# +# NOTICE: All information contained herein is, and remains +# the property of Elasticsearch B.V. and its suppliers, if any. +# The intellectual and technical concepts contained herein +# are proprietary to Elasticsearch B.V. and its suppliers and +# may be covered by U.S. and Foreign Patents, patents in +# process, and are protected by trade secret or copyright +# law. Dissemination of this information or reproduction of +# this material is strictly forbidden unless prior written +# permission is obtained from Elasticsearch B.V. + +.PHONY: api-docs +api-docs: ## Generate kibana.serverless.yaml + @npx @redocly/cli join "kibana.info.serverless.yaml" "../x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml" "../x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml" "../src/plugins/data_views/docs/openapi/bundled.yaml" "../x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml" "../packages/core/saved-objects/docs/openapi/bundled_serverless.yaml" -o "kibana.serverless.yaml" --prefix-components-with-info-prop title + +.PHONY: api-docs-lint +api-docs-lint: ## Run spectral API docs linter + @npx @stoplight/spectral-cli lint "kibana.serverless.yaml" --ruleset ".spectral.yaml" + +help: ## Display help + @awk 'BEGIN {FS = ":.*##"; printf "Usage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) +#------------- -------------- + +.DEFAULT_GOAL := help + From 08561554ef7d5c5d18a7a8ef5d545d3bed8ac4db Mon Sep 17 00:00:00 2001 From: Mark Hopkin Date: Wed, 19 Jun 2024 16:59:14 +0100 Subject: [PATCH 102/123] [Entity Analytics] Asset criticality bulk upload JSON API (#186310) ## Summary Add the asset criticality bulk upload API at `POST /api/asset_criticality/bulk`. Records supplied will either be created or updated. This API has the same functionality as the csv upload API but takes a JSON body. A couple slight differences: - only 1000 records can be supplied, I think this is a good number, I have capped this so we dont have to parse a huge body, I think if users want more than this in a single request they can use CSV which is better suited (parses request as data is received instead of parsing in one go) - Validation is done up front not line by line, if an invalid record is received the whole request is aborted with a 400, no records are changed or added. - Example curl (note asset criticality advanced setting must be enabled otherwise you will get a 403): ``` > curl -X POST $KIBANA_URL/api/asset_criticality/bulk \ --header "kbn-xsrf: true" \ --header "Content-Type: application/json" \ --header "elastic-api-version: 2023-10-31" \ --data '{ "records": [ { "id_field": "host.name", "id_value": "host-1", "criticality_level": "low_impact" }, { "id_field": "host.name", "id_value": "host-2", "criticality_level": "high_impact" } ] }' ``` I have added API tests for the new route --- .../bulk_upload_asset_criticality.gen.ts | 24 ++++ .../bulk_upload_asset_criticality.schema.yaml | 52 +++++++++ .../asset_criticality/common.gen.ts | 29 +++++ .../asset_criticality/common.schema.yaml | 53 ++++++++- .../create_asset_criticality.schema.yaml | 4 +- .../asset_criticality/index.ts | 2 +- .../upload_asset_criticality_csv.gen.ts | 36 ------ .../upload_asset_criticality_csv.schema.yaml | 47 +------- .../asset_criticality/constants.ts | 2 + .../public/entity_analytics/api/api.ts | 6 +- .../components/result_step.tsx | 4 +- .../reducer.test.ts | 4 +- .../reducer.ts | 6 +- .../asset_criticality_data_client.ts | 8 +- .../asset_criticality/routes/bulk_upload.ts | 106 ++++++++++++++++++ .../register_asset_criticality_routes.ts | 2 + .../asset_criticality/routes/upload_csv.ts | 4 +- .../asset_criticality/routes/upsert.ts | 8 +- .../lib/telemetry/event_based/events.ts | 8 +- .../asset_criticality.ts | 104 +++++++++++++++++ .../utils/asset_criticality.ts | 18 ++- 21 files changed, 418 insertions(+), 109 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/bulk_upload_asset_criticality.gen.ts create mode 100644 x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/bulk_upload_asset_criticality.schema.yaml delete mode 100644 x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.gen.ts create mode 100644 x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/bulk_upload.ts diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/bulk_upload_asset_criticality.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/bulk_upload_asset_criticality.gen.ts new file mode 100644 index 00000000000000..c0d00e394b6b1f --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/bulk_upload_asset_criticality.gen.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Asset Criticality Bulk Upsert Schema + * version: 1 + */ + +import { z } from 'zod'; + +import { CreateAssetCriticalityRecord } from './common.gen'; + +export type AssetCriticalityBulkUploadRequest = z.infer; +export const AssetCriticalityBulkUploadRequest = z.object({ + records: z.array(CreateAssetCriticalityRecord).min(1).max(1000), +}); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/bulk_upload_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/bulk_upload_asset_criticality.schema.yaml new file mode 100644 index 00000000000000..b4b7d5d2f1fe4c --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/bulk_upload_asset_criticality.schema.yaml @@ -0,0 +1,52 @@ +openapi: 3.0.0 +info: + version: '1' + title: Asset Criticality Bulk Upsert Schema +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + /api/asset_criticality/bulk: + post: + x-labels: [ess, serverless] + summary: Bulk upsert asset criticality data, creating or updating records as needed + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AssetCriticalityBulkUploadRequest' + + responses: + '200': + description: Bulk upload successful + content: + application/json: + schema: + $ref: './common.schema.yaml#/components/schemas/AssetCriticalityBulkUploadResponse' + '413': + description: File too large +components: + schemas: + AssetCriticalityBulkUploadRequest: + type: object + example: + records: + - id_value: 'host-1' + id_field: 'host.name' + criticality_level: 'low_impact' + - id_value: 'host-2' + id_field: 'host.name' + criticality_level: 'medium_impact' + properties: + records: + type: array + minItems: 1 + maxItems: 1000 + items: + $ref: './common.schema.yaml#/components/schemas/CreateAssetCriticalityRecord' + required: + - records diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts index feff1e5126b787..4b689d22944e1f 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts @@ -50,6 +50,14 @@ export type CreateAssetCriticalityRecord = z.infer; +export const CreateSingleAssetCriticalityRequest = CreateAssetCriticalityRecord.merge( + z.object({ /** * If 'wait_for' the request will wait for the index refresh. */ @@ -76,3 +84,24 @@ export const AssetCriticalityRecord = CreateAssetCriticalityRecord.merge( '@timestamp': z.string().datetime(), }) ); + +export type AssetCriticalityBulkUploadErrorItem = z.infer< + typeof AssetCriticalityBulkUploadErrorItem +>; +export const AssetCriticalityBulkUploadErrorItem = z.object({ + message: z.string(), + index: z.number().int(), +}); + +export type AssetCriticalityBulkUploadStats = z.infer; +export const AssetCriticalityBulkUploadStats = z.object({ + successful: z.number().int(), + failed: z.number().int(), + total: z.number().int(), +}); + +export type AssetCriticalityBulkUploadResponse = z.infer; +export const AssetCriticalityBulkUploadResponse = z.object({ + errors: z.array(AssetCriticalityBulkUploadErrorItem), + stats: AssetCriticalityBulkUploadStats, +}); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml index 294cba2dd89ea2..3218ec07e0fe23 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml @@ -49,7 +49,6 @@ components: - high_impact - extreme_impact description: The criticality level of the asset. - CreateAssetCriticalityRecord: allOf: - $ref: '#/components/schemas/AssetCriticalityRecordIdParts' @@ -57,12 +56,17 @@ components: properties: criticality_level: $ref: '#/components/schemas/AssetCriticalityLevel' + required: + - criticality_level + CreateSingleAssetCriticalityRequest: + allOf: + - $ref: '#/components/schemas/CreateAssetCriticalityRecord' + - type: object + properties: refresh: type: string enum: [wait_for] description: If 'wait_for' the request will wait for the index refresh. - required: - - criticality_level DeleteAssetCriticalityRecord: allOf: - $ref: '#/components/schemas/AssetCriticalityRecordIdParts' @@ -84,3 +88,46 @@ components: description: The time the record was created or updated. required: - '@timestamp' + AssetCriticalityBulkUploadErrorItem: + type: object + properties: + message: + type: string + index: + type: integer + required: + - message + - index + AssetCriticalityBulkUploadStats: + type: object + properties: + successful: + type: integer + failed: + type: integer + total: + type: integer + required: + - successful + - failed + - total + AssetCriticalityBulkUploadResponse: + type: object + example: + errors: + - message: 'Invalid ID field' + index: 0 + stats: + successful: 1 + failed: 1 + total: 2 + properties: + errors: + type: array + items: + $ref: '#/components/schemas/AssetCriticalityBulkUploadErrorItem' + stats: + $ref: '#/components/schemas/AssetCriticalityBulkUploadStats' + required: + - errors + - stats diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml index 4b5e52b5eb2112..d59ce99c8717c3 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/create_asset_criticality.schema.yaml @@ -21,7 +21,7 @@ paths: content: application/json: schema: - $ref: './common.schema.yaml#/components/schemas/CreateAssetCriticalityRecord' + $ref: './common.schema.yaml#/components/schemas/CreateSingleAssetCriticalityRequest' responses: '200': description: Successful response @@ -41,7 +41,7 @@ paths: content: application/json: schema: - $ref: './common.schema.yaml#/components/schemas/CreateAssetCriticalityRecord' + $ref: './common.schema.yaml#/components/schemas/CreateSingleAssetCriticalityRequest' responses: '200': description: Successful response diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts index cc79a94a41fcbe..5394f0c9cf69f3 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/index.ts @@ -7,5 +7,5 @@ export * from './common.gen'; export * from './get_asset_criticality_status.gen'; -export * from './upload_asset_criticality_csv.gen'; export * from './get_asset_criticality_privileges.gen'; +export * from './bulk_upload_asset_criticality.gen'; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.gen.ts deleted file mode 100644 index dcad4f6596bac4..00000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.gen.ts +++ /dev/null @@ -1,36 +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. - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Asset Criticality Create Record Schema - * version: 1 - */ - -import { z } from 'zod'; - -export type ErrorItem = z.infer; -export const ErrorItem = z.object({ - message: z.string(), - index: z.number().int(), -}); - -export type Stats = z.infer; -export const Stats = z.object({ - successful: z.number().int(), - failed: z.number().int(), - total: z.number().int(), -}); - -export type AssetCriticalityCsvUploadResponse = z.infer; -export const AssetCriticalityCsvUploadResponse = z.object({ - errors: z.array(ErrorItem), - stats: Stats, -}); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.schema.yaml index 933839cea43a34..c348dcefa8b781 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/asset_criticality/upload_asset_criticality_csv.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: version: '1' - title: Asset Criticality Create Record Schema + title: Asset Criticality CSV Upload Schema servers: - url: 'http://{kibana_host}:{port}' variables: @@ -29,11 +29,11 @@ paths: - file responses: '200': - description: CSV upload successful + description: Bulk upload successful content: application/json: schema: - $ref: '#/components/schemas/AssetCriticalityCsvUploadResponse' + $ref: '#./common/components/schemas/AssetCriticalityBulkUploadResponse' '413': description: File too large /api/asset_criticality/upload_csv: @@ -55,47 +55,10 @@ paths: - file responses: '200': - description: CSV upload successful + description: Bulk upload successful content: application/json: schema: - $ref: '#/components/schemas/AssetCriticalityCsvUploadResponse' + $ref: '#./common/components/schemas/AssetCriticalityBulkUploadResponse' '413': description: File too large -components: - schemas: - ErrorItem: - type: object - properties: - message: - type: string - index: - type: integer - required: - - message - - index - Stats: - type: object - properties: - successful: - type: integer - failed: - type: integer - total: - type: integer - required: - - successful - - failed - - total - AssetCriticalityCsvUploadResponse: - type: object - properties: - errors: - type: array - items: - $ref: '#/components/schemas/ErrorItem' - stats: - $ref: '#/components/schemas/Stats' - required: - - errors - - stats diff --git a/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts b/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts index d7d9854834d098..42be15209624c2 100644 --- a/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts +++ b/x-pack/plugins/security_solution/common/entity_analytics/asset_criticality/constants.ts @@ -16,6 +16,8 @@ export const ASSET_CRITICALITY_INTERNAL_CSV_UPLOAD_URL = export const ASSET_CRITICALITY_PUBLIC_URL = `/api/asset_criticality` as const; export const ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL = `${ASSET_CRITICALITY_PUBLIC_URL}/upload_csv` as const; +export const ASSET_CRITICALITY_PUBLIC_BULK_UPLOAD_URL = + `${ASSET_CRITICALITY_PUBLIC_URL}/bulk` as const; export const ASSET_CRITICALITY_INDEX_PATTERN = '.asset-criticality.asset-criticality-*'; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts index da391a9b30432a..aa3b432533027c 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/api.ts @@ -18,7 +18,7 @@ import type { RiskScoresEntityCalculationRequest, RiskScoresEntityCalculationResponse, } from '../../../common/api/entity_analytics/risk_engine/entity_calculation_route.gen'; -import type { AssetCriticalityCsvUploadResponse } from '../../../common/entity_analytics/asset_criticality/types'; +import type { AssetCriticalityBulkUploadResponse } from '../../../common/entity_analytics/asset_criticality/types'; import type { AssetCriticalityRecord, EntityAnalyticsPrivileges, @@ -181,12 +181,12 @@ export const useEntityAnalyticsRoutes = () => { const uploadAssetCriticalityFile = async ( fileContent: string, fileName: string - ): Promise => { + ): Promise => { const file = new File([new Blob([fileContent])], fileName, { type: 'text/csv' }); const body = new FormData(); body.append('file', file); - return http.fetch( + return http.fetch( ASSET_CRITICALITY_PUBLIC_CSV_UPLOAD_URL, { version: API_VERSIONS.public.v1, diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx index 30834f2fb8c323..1652c85eace1f8 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx @@ -18,11 +18,11 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; -import type { AssetCriticalityCsvUploadResponse } from '../../../../../common/entity_analytics/asset_criticality/types'; +import type { AssetCriticalityBulkUploadResponse } from '../../../../../common/entity_analytics/asset_criticality/types'; import { buildAnnotationsFromError } from '../helpers'; export const AssetCriticalityResultStep: React.FC<{ - result?: AssetCriticalityCsvUploadResponse; + result?: AssetCriticalityBulkUploadResponse; validLinesAsText: string; errorMessage?: string; onReturn: () => void; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/reducer.test.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/reducer.test.ts index 68f7814d3113a7..60b6191a777d61 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/reducer.test.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/reducer.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AssetCriticalityCsvUploadResponse } from '../../../../common/api/entity_analytics'; +import type { AssetCriticalityBulkUploadResponse } from '../../../../common/api/entity_analytics'; import type { ReducerAction, ReducerState, ValidationStepState } from './reducer'; import { reducer } from './reducer'; import { FileUploaderSteps } from './types'; @@ -43,7 +43,7 @@ describe('reducer', () => { }); it('should handle "fileUploaded" action with response', () => { - const response: AssetCriticalityCsvUploadResponse = { + const response: AssetCriticalityBulkUploadResponse = { errors: [], stats: { total: 10, diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/reducer.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/reducer.ts index 0868caf2d624be..e7f233015434f1 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/reducer.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/reducer.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AssetCriticalityCsvUploadResponse } from '../../../../common/entity_analytics/asset_criticality/types'; +import type { AssetCriticalityBulkUploadResponse } from '../../../../common/entity_analytics/asset_criticality/types'; import { FileUploaderSteps } from './types'; import type { ValidatedFile } from './types'; import { isFilePickerStep, isValidationStep } from './helpers'; @@ -26,7 +26,7 @@ export interface ValidationStepState { export interface ResultStepState { step: FileUploaderSteps.RESULT; - fileUploadResponse?: AssetCriticalityCsvUploadResponse; + fileUploadResponse?: AssetCriticalityBulkUploadResponse; fileUploadError?: string; validLinesAsText: string; } @@ -46,7 +46,7 @@ export type ReducerAction = | { type: 'uploadingFile' } | { type: 'fileUploaded'; - payload: { response?: AssetCriticalityCsvUploadResponse; errorMessage?: string }; + payload: { response?: AssetCriticalityBulkUploadResponse; errorMessage?: string }; }; export const INITIAL_STATE: FilePickerState = { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts index fd5c2921972f35..c5abf75b714784 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/asset_criticality_data_client.ts @@ -10,7 +10,7 @@ import type { Logger, ElasticsearchClient } from '@kbn/core/server'; import { mappingFromFieldMap } from '@kbn/alerting-plugin/common'; import type { AuditLogger } from '@kbn/security-plugin-types-server'; import type { - AssetCriticalityCsvUploadResponse, + AssetCriticalityBulkUploadResponse, AssetCriticalityUpsert, } from '../../../../common/entity_analytics/asset_criticality/types'; import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics'; @@ -183,9 +183,9 @@ export class AssetCriticalityDataClient { recordsStream, flushBytes, retries, - }: BulkUpsertFromStreamOptions): Promise => { - const errors: AssetCriticalityCsvUploadResponse['errors'] = []; - const stats: AssetCriticalityCsvUploadResponse['stats'] = { + }: BulkUpsertFromStreamOptions): Promise => { + const errors: AssetCriticalityBulkUploadResponse['errors'] = []; + const stats: AssetCriticalityBulkUploadResponse['stats'] = { successful: 0, failed: 0, total: 0, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/bulk_upload.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/bulk_upload.ts new file mode 100644 index 00000000000000..efc03a4adacd0e --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/bulk_upload.ts @@ -0,0 +1,106 @@ +/* + * 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 { Logger } from '@kbn/core/server'; +import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import { Readable } from 'node:stream'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import type { AssetCriticalityBulkUploadResponse } from '../../../../../common/api/entity_analytics'; +import { AssetCriticalityBulkUploadRequest } from '../../../../../common/api/entity_analytics'; +import type { ConfigType } from '../../../../config'; +import { + ASSET_CRITICALITY_PUBLIC_BULK_UPLOAD_URL, + APP_ID, + ENABLE_ASSET_CRITICALITY_SETTING, + API_VERSIONS, +} from '../../../../../common/constants'; +import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; +import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setting_enabled'; +import type { EntityAnalyticsRoutesDeps } from '../../types'; +import { AssetCriticalityAuditActions } from '../audit'; +import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; + +export const assetCriticalityPublicBulkUploadRoute = ( + router: EntityAnalyticsRoutesDeps['router'], + logger: Logger, + config: ConfigType +) => { + router.versioned + .post({ + access: 'public', + path: ASSET_CRITICALITY_PUBLIC_BULK_UPLOAD_URL, + options: { + tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`], + }, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + body: buildRouteValidationWithZod(AssetCriticalityBulkUploadRequest), + }, + }, + }, + async (context, request, response) => { + const { errorRetries, maxBulkRequestBodySizeBytes } = + config.entityAnalytics.assetCriticality.csvUpload; + const { records } = request.body; + + const securitySolution = await context.securitySolution; + securitySolution.getAuditLogger()?.log({ + message: 'User attempted to assign many asset criticalities via bulk upload', + event: { + action: AssetCriticalityAuditActions.ASSET_CRITICALITY_BULK_UPDATE, + category: AUDIT_CATEGORY.DATABASE, + type: AUDIT_TYPE.CREATION, + outcome: AUDIT_OUTCOME.UNKNOWN, + }, + }); + + const start = new Date(); + const siemResponse = buildSiemResponse(response); + + try { + await assertAdvancedSettingsEnabled(await context.core, ENABLE_ASSET_CRITICALITY_SETTING); + await checkAndInitAssetCriticalityResources(context, logger); + const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient(); + + const formattedRecords = records.map((record) => ({ + idField: record.id_field, + idValue: record.id_value, + criticalityLevel: record.criticality_level, + })); + + const recordsStream = Readable.from(formattedRecords, { objectMode: true }); + + const { errors, stats } = await assetCriticalityClient.bulkUpsertFromStream({ + recordsStream, + retries: errorRetries, + flushBytes: maxBulkRequestBodySizeBytes, + }); + const end = new Date(); + + const tookMs = end.getTime() - start.getTime(); + logger.debug( + `Asset criticality Bulk upload completed in ${tookMs}ms ${JSON.stringify(stats)}` + ); + + const resBody: AssetCriticalityBulkUploadResponse = { errors, stats }; + + return response.ok({ body: resBody }); + } catch (e) { + logger.error(`Error during asset criticality bulk upload: ${e}`); + const error = transformError(e); + return siemResponse.error({ + statusCode: error.statusCode, + body: error.message, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts index c211b1260b6648..1f380de7df300c 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/register_asset_criticality_routes.ts @@ -14,6 +14,7 @@ import { assetCriticalityPublicCSVUploadRoute, } from './upload_csv'; import type { EntityAnalyticsRoutesDeps } from '../../types'; +import { assetCriticalityPublicBulkUploadRoute } from './bulk_upload'; export const registerAssetCriticalityRoutes = ({ router, @@ -31,6 +32,7 @@ export const registerAssetCriticalityRoutes = ({ // Public routes assetCriticalityPublicCSVUploadRoute(router, logger, config, getStartServices); + assetCriticalityPublicBulkUploadRoute(router, logger, config); assetCriticalityPublicDeleteRoute(router, logger); assetCriticalityPublicGetRoute(router, logger); assetCriticalityPublicUpsertRoute(router, logger); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts index bd0a64fb08da78..9c9fa19ca3cbd0 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upload_csv.ts @@ -10,7 +10,7 @@ import { schema } from '@kbn/config-schema'; import Papa from 'papaparse'; import { transformError } from '@kbn/securitysolution-es-utils'; import type internal from 'stream'; -import type { AssetCriticalityCsvUploadResponse } from '../../../../../common/api/entity_analytics'; +import type { AssetCriticalityBulkUploadResponse } from '../../../../../common/api/entity_analytics'; import { CRITICALITY_CSV_MAX_SIZE_BYTES_WITH_TOLERANCE } from '../../../../../common/entity_analytics/asset_criticality'; import type { ConfigType } from '../../../../config'; import type { HapiReadableStream, SecuritySolutionRequestHandlerContext } from '../../../../types'; @@ -88,7 +88,7 @@ const handler: ( logger.debug(`Asset criticality CSV upload completed in ${tookMs}ms ${JSON.stringify(stats)}`); // type assignment here to ensure that the response body stays in sync with the API schema - const resBody: AssetCriticalityCsvUploadResponse = { errors, stats }; + const resBody: AssetCriticalityBulkUploadResponse = { errors, stats }; const [eventType, event] = createAssetCriticalityProcessedFileEvent({ startTime: start, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts index 78fbe297862986..cb3c36f450e430 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/asset_criticality/routes/upsert.ts @@ -17,7 +17,7 @@ import { API_VERSIONS, } from '../../../../../common/constants'; import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources'; -import { CreateAssetCriticalityRecord } from '../../../../../common/api/entity_analytics'; +import { CreateSingleAssetCriticalityRequest } from '../../../../../common/api/entity_analytics'; import type { EntityAnalyticsRoutesDeps } from '../../types'; import { AssetCriticalityAuditActions } from '../audit'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../../audit'; @@ -26,7 +26,7 @@ import { assertAdvancedSettingsEnabled } from '../../utils/assert_advanced_setti type UpsertHandler = ( context: SecuritySolutionRequestHandlerContext, request: { - body: CreateAssetCriticalityRecord; + body: CreateSingleAssetCriticalityRequest; }, response: KibanaResponseFactory ) => Promise; @@ -93,7 +93,7 @@ export const assetCriticalityInternalUpsertRoute = ( version: API_VERSIONS.internal.v1, validate: { request: { - body: buildRouteValidationWithZod(CreateAssetCriticalityRecord), + body: buildRouteValidationWithZod(CreateSingleAssetCriticalityRequest), }, }, }, @@ -118,7 +118,7 @@ export const assetCriticalityPublicUpsertRoute = ( version: API_VERSIONS.public.v1, validate: { request: { - body: buildRouteValidationWithZod(CreateAssetCriticalityRecord), + body: buildRouteValidationWithZod(CreateSingleAssetCriticalityRequest), }, }, }, diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts b/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts index 03552f02e39cfb..97a4d44fcd5949 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/event_based/events.ts @@ -5,7 +5,7 @@ * 2.0. */ import type { EventTypeOpts } from '@kbn/core/server'; -import type { AssetCriticalityCsvUploadResponse } from '../../../../common/api/entity_analytics'; +import type { AssetCriticalityBulkUploadResponse } from '../../../../common/api/entity_analytics'; export const RISK_SCORE_EXECUTION_SUCCESS_EVENT: EventTypeOpts<{ scoresWritten: number; @@ -88,7 +88,7 @@ interface AssetCriticalitySystemProcessedAssignmentFileEvent { endTime: string; tookMs: number; }; - result?: AssetCriticalityCsvUploadResponse['stats']; + result?: AssetCriticalityBulkUploadResponse['stats']; status: 'success' | 'partial_success' | 'fail'; } @@ -124,7 +124,7 @@ export const ASSET_CRITICALITY_SYSTEM_PROCESSED_ASSIGNMENT_FILE_EVENT: EventType }; interface CreateAssetCriticalityProcessedFileEvent { - result?: AssetCriticalityCsvUploadResponse['stats']; + result?: AssetCriticalityBulkUploadResponse['stats']; startTime: Date; endTime: Date; } @@ -154,7 +154,7 @@ export const createAssetCriticalityProcessedFileEvent = ({ ]; }; -const getUploadStatus = (stats?: AssetCriticalityCsvUploadResponse['stats']) => { +const getUploadStatus = (stats?: AssetCriticalityBulkUploadResponse['stats']) => { if (!stats) { return 'fail'; } diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/asset_criticality.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/asset_criticality.ts index 7a7f50c5741eca..fa3f3e0e67f38f 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/asset_criticality.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/asset_criticality.ts @@ -6,6 +6,8 @@ */ import expect from '@kbn/expect'; +import { omit } from 'lodash'; +import { CreateAssetCriticalityRecord } from '@kbn/security-solution-plugin/common/api/entity_analytics'; import { cleanRiskEngine, cleanAssetCriticality, @@ -206,6 +208,108 @@ export default ({ getService }: FtrProviderContext) => { }); }); + describe('bulk upload', () => { + const expectAssetCriticalityDocMatching = async (expectedDoc: { + id_field: string; + id_value: string; + criticality_level: string; + }) => { + const esDoc = await getAssetCriticalityDoc({ + es, + idField: expectedDoc.id_field, + idValue: expectedDoc.id_value, + }); + + expect(omit(esDoc, '@timestamp')).to.eql(expectedDoc); + }; + + it('should return 400 if the records array is empty', async () => { + await assetCriticalityRoutes.bulkUpload([], { + expectStatusCode: 400, + }); + }); + + it('should return 400 if the records array is too large', async () => { + const records = new Array(1001).fill({ + id_field: 'host.name', + id_value: 'host-1', + criticality_level: 'high_impact', + }); + + await assetCriticalityRoutes.bulkUpload(records, { + expectStatusCode: 400, + }); + }); + + it('should return a 403 if the advanced setting is disabled', async () => { + await disableAssetCriticalityAdvancedSetting(kibanaServer, log); + + const validRecord: CreateAssetCriticalityRecord = { + id_field: 'host.name', + id_value: 'delete-me', + criticality_level: 'high_impact', + }; + + await assetCriticalityRoutes.bulkUpload([validRecord], { + expectStatusCode: 403, + }); + }); + + it('should correctly upload a valid record for one entity', async () => { + const validRecord: CreateAssetCriticalityRecord = { + id_field: 'host.name', + id_value: 'host-1', + criticality_level: 'high_impact', + }; + + const { body } = await assetCriticalityRoutes.bulkUpload([validRecord]); + expect(body.errors).to.eql([]); + expect(body.stats).to.eql({ + total: 1, + successful: 1, + failed: 0, + }); + + await expectAssetCriticalityDocMatching(validRecord); + }); + + it('should correctly upload valid records for multiple entities', async () => { + const validRecords: CreateAssetCriticalityRecord[] = Array.from({ length: 50 }, (_, i) => ({ + id_field: 'host.name', + id_value: `host-${i}`, + criticality_level: 'high_impact', + })); + + const { body } = await assetCriticalityRoutes.bulkUpload(validRecords); + expect(body.errors).to.eql([]); + expect(body.stats).to.eql({ + total: validRecords.length, + successful: validRecords.length, + failed: 0, + }); + + await Promise.all(validRecords.map(expectAssetCriticalityDocMatching)); + }); + + it('should return a 400 if a record is invalid', async () => { + const invalidRecord = { + id_field: 'host.name', + id_value: 'host-1', + criticality_level: 'invalid', + } as unknown as CreateAssetCriticalityRecord; + + const validRecord: CreateAssetCriticalityRecord = { + id_field: 'host.name', + id_value: 'host-2', + criticality_level: 'high_impact', + }; + + await assetCriticalityRoutes.bulkUpload([invalidRecord, validRecord], { + expectStatusCode: 400, + }); + }); + }); + describe('delete', () => { it('should correctly delete asset criticality', async () => { const assetCriticality = { diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts index da786269519db9..ac7dfd170e4125 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/asset_criticality.ts @@ -17,8 +17,12 @@ import { ASSET_CRITICALITY_INTERNAL_PRIVILEGES_URL, ENABLE_ASSET_CRITICALITY_SETTING, API_VERSIONS, + ASSET_CRITICALITY_PUBLIC_BULK_UPLOAD_URL, } from '@kbn/security-solution-plugin/common/constants'; -import type { AssetCriticalityRecord } from '@kbn/security-solution-plugin/common/api/entity_analytics'; +import type { + AssetCriticalityRecord, + CreateAssetCriticalityRecord, +} from '@kbn/security-solution-plugin/common/api/entity_analytics'; import type { Client } from '@elastic/elasticsearch'; import type { ToolingLog } from '@kbn/tooling-log'; import querystring from 'querystring'; @@ -155,6 +159,18 @@ export const assetCriticalityRouteHelpersFactory = ( .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .expect(expectStatusCode); }, + bulkUpload: async ( + records: CreateAssetCriticalityRecord[], + { expectStatusCode }: { expectStatusCode: number } = { expectStatusCode: 200 } + ) => { + return supertest + .post(routeWithNamespace(ASSET_CRITICALITY_PUBLIC_BULK_UPLOAD_URL, namespace)) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, API_VERSIONS.public.v1) + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send({ records }) + .expect(expectStatusCode); + }, uploadCsv: async ( fileContent: string | Buffer, { expectStatusCode }: { expectStatusCode: number } = { expectStatusCode: 200 } From 06f773934a1b3dc44355563cf4ff2274f3d325eb Mon Sep 17 00:00:00 2001 From: Ryan Keairns Date: Wed, 19 Jun 2024 09:46:20 -0700 Subject: [PATCH 103/123] [ES|QL] Set custom highlight colors for suggest widget (#186476) ## Summary Set custom theme colors for highlights in the suggest widget. *Dark mode* ![CleanShot 2024-06-19 at 08 10 32@2x](https://github.com/elastic/kibana/assets/446285/ced95d75-a5c5-4780-a9f8-188e2432ee31) *Light mode* ![CleanShot 2024-06-19 at 08 09 40@2x](https://github.com/elastic/kibana/assets/446285/7d3c6292-a9f3-4bb4-a4f9-df6fa8274c39) ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --- packages/kbn-monaco/src/esql/lib/esql_theme.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/kbn-monaco/src/esql/lib/esql_theme.ts b/packages/kbn-monaco/src/esql/lib/esql_theme.ts index c88a8fc02b26df..80f9fc54009890 100644 --- a/packages/kbn-monaco/src/esql/lib/esql_theme.ts +++ b/packages/kbn-monaco/src/esql/lib/esql_theme.ts @@ -145,7 +145,9 @@ export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({ 'editor.selectionHighlightBorder': euiThemeVars.euiColorLightShade, 'editorSuggestWidget.background': euiThemeVars.euiColorEmptyShade, 'editorSuggestWidget.border': euiThemeVars.euiColorEmptyShade, + 'editorSuggestWidget.focusHighlightForeground': euiThemeVars.euiColorEmptyShade, 'editorSuggestWidget.foreground': euiThemeVars.euiTextColor, + 'editorSuggestWidget.highlightForeground': euiThemeVars.euiColorPrimary, 'editorSuggestWidget.selectedBackground': euiThemeVars.euiColorPrimary, 'editorSuggestWidget.selectedForeground': euiThemeVars.euiColorEmptyShade, }, From 57891ff3534781bd558b680bc511427646c774c2 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Wed, 19 Jun 2024 14:17:26 -0300 Subject: [PATCH 104/123] [Discover] Add support for contextual awareness functional tests (#185905) ## Summary This PR adds functional test support for the Discover contextual awareness framework, and adds tests for the initial `getCellRenderers` extension point using example profiles. To support this, this PR introduces a new YAML setting called `discover.experimental.enabledProfiles` which can be used to selectively enable profiles both for functional testing and demoing WIP profiles that aren't yet ready for GA. Example usage: ```yml discover.experimental.enabledProfiles: ['example-root-profile', 'example-data-source-profile', 'example-document-profile'] ``` Flaky test runs: - Stateful x50: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6304 - Serverless Observability x50: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6305 - Serverless Search x50: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6306 - Serverless Security x50: https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6307 Resolves #184699. ### Checklist - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .buildkite/ftr_configs.yml | 4 + src/plugins/discover/common/config.ts | 3 +- .../context_awareness/__mocks__/index.ts | 21 +-- .../example_data_source_profile/index.ts | 9 ++ .../example_data_source_profile/profile.tsx | 83 ++++++++++++ .../example_document_profile/index.ts | 9 ++ .../example_document_profile/profile.ts | 32 +++++ .../example_root_pofile/index.ts | 9 ++ .../example_root_pofile/profile.tsx | 42 ++++++ .../profile_providers/index.ts | 9 ++ .../log_document_profile/profile.ts | 2 +- .../logs_data_source_profile/profile.ts | 2 +- .../profile_provider_services.ts | 0 .../register_profile_providers.test.ts | 117 +++++++++++++++++ .../register_profile_providers.ts | 85 ++++++++++++ .../context_awareness/profile_service.ts | 45 +++---- .../profiles/data_source_profile.ts | 12 +- .../profiles/document_profile.ts | 12 +- .../profiles/example_profiles.tsx | 123 ------------------ .../profiles/root_profile.ts | 12 +- src/plugins/discover/public/plugin.tsx | 63 ++++----- .../context_awareness/_data_source_profile.ts | 97 ++++++++++++++ .../context_awareness/_root_profile.ts | 52 ++++++++ .../apps/discover/context_awareness/config.ts | 26 ++++ .../apps/discover/context_awareness/index.ts | 39 ++++++ .../discover/context_awareness/data.json.gz | Bin 0 -> 351 bytes .../discover/context_awareness/mappings.json | 76 +++++++++++ .../discover/context_awareness.json | 49 +++++++ .../test_suites/core_plugins/rendering.ts | 1 + .../context_awareness/_data_source_profile.ts | 88 +++++++++++++ .../context_awareness/_root_profile.ts | 47 +++++++ .../discover/context_awareness/index.ts | 40 ++++++ .../observability/config.context_awareness.ts | 22 ++++ .../search/config.context_awareness.ts | 22 ++++ .../security/config.context_awareness.ts | 22 ++++ 35 files changed, 1072 insertions(+), 203 deletions(-) create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/index.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/index.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/index.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/profile.tsx create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/index.ts rename src/plugins/discover/public/context_awareness/{profiles => profile_providers}/profile_provider_services.ts (100%) create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts create mode 100644 src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.ts delete mode 100644 src/plugins/discover/public/context_awareness/profiles/example_profiles.tsx create mode 100644 test/functional/apps/discover/context_awareness/_data_source_profile.ts create mode 100644 test/functional/apps/discover/context_awareness/_root_profile.ts create mode 100644 test/functional/apps/discover/context_awareness/config.ts create mode 100644 test/functional/apps/discover/context_awareness/index.ts create mode 100644 test/functional/fixtures/es_archiver/discover/context_awareness/data.json.gz create mode 100644 test/functional/fixtures/es_archiver/discover/context_awareness/mappings.json create mode 100644 test/functional/fixtures/kbn_archiver/discover/context_awareness.json create mode 100644 x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/_data_source_profile.ts create mode 100644 x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/_root_profile.ts create mode 100644 x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts create mode 100644 x-pack/test_serverless/functional/test_suites/observability/config.context_awareness.ts create mode 100644 x-pack/test_serverless/functional/test_suites/search/config.context_awareness.ts create mode 100644 x-pack/test_serverless/functional/test_suites/security/config.context_awareness.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index 55f23715e3468f..8e558458feb04c 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -127,6 +127,7 @@ enabled: - test/functional/apps/discover/group6/config.ts - test/functional/apps/discover/group7/config.ts - test/functional/apps/discover/group8/config.ts + - test/functional/apps/discover/context_awareness/config.ts - test/functional/apps/getting_started/config.ts - test/functional/apps/home/config.ts - test/functional/apps/kibana_overview/config.ts @@ -426,6 +427,7 @@ enabled: - x-pack/test_serverless/functional/test_suites/observability/config.ts - x-pack/test_serverless/functional/test_suites/observability/config.examples.ts - x-pack/test_serverless/functional/test_suites/observability/config.saved_objects_management.ts + - x-pack/test_serverless/functional/test_suites/observability/config.context_awareness.ts - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group2.ts - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group3.ts @@ -438,6 +440,7 @@ enabled: - x-pack/test_serverless/functional/test_suites/search/config.examples.ts - x-pack/test_serverless/functional/test_suites/search/config.screenshots.ts - x-pack/test_serverless/functional/test_suites/search/config.saved_objects_management.ts + - x-pack/test_serverless/functional/test_suites/search/config.context_awareness.ts - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group2.ts - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group3.ts @@ -449,6 +452,7 @@ enabled: - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.essentials.ts - x-pack/test_serverless/functional/test_suites/security/config.saved_objects_management.ts + - x-pack/test_serverless/functional/test_suites/security/config.context_awareness.ts - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group2.ts - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group3.ts diff --git a/src/plugins/discover/common/config.ts b/src/plugins/discover/common/config.ts index f3afc0ebf08be8..272f81b77d5a89 100644 --- a/src/plugins/discover/common/config.ts +++ b/src/plugins/discover/common/config.ts @@ -13,9 +13,10 @@ export const configSchema = schema.object({ experimental: schema.maybe( schema.object({ ruleFormV2Enabled: schema.maybe(schema.boolean({ defaultValue: false })), + enabledProfiles: schema.maybe(schema.arrayOf(schema.string(), { defaultValue: [] })), }) ), }); export type ConfigSchema = TypeOf; -export type ExperimentalFeatures = ConfigSchema['experimental']; +export type ExperimentalFeatures = NonNullable; diff --git a/src/plugins/discover/public/context_awareness/__mocks__/index.ts b/src/plugins/discover/public/context_awareness/__mocks__/index.ts index c13dd806761486..fbdb13a2e5648f 100644 --- a/src/plugins/discover/public/context_awareness/__mocks__/index.ts +++ b/src/plugins/discover/public/context_awareness/__mocks__/index.ts @@ -19,10 +19,12 @@ import { RootProfileService, SolutionType, } from '../profiles'; -import { createProfileProviderServices } from '../profiles/profile_provider_services'; +import { createProfileProviderServices } from '../profile_providers/profile_provider_services'; import { ProfilesManager } from '../profiles_manager'; -export const createContextAwarenessMocks = () => { +export const createContextAwarenessMocks = ({ + shouldRegisterProviders = true, +}: { shouldRegisterProviders?: boolean } = {}) => { const rootProfileProviderMock: RootProfileProvider = { profileId: 'root-profile', profile: { @@ -92,15 +94,15 @@ export const createContextAwarenessMocks = () => { const records = getDataTableRecords(dataViewWithTimefieldMock); const contextRecordMock = records[0]; const contextRecordMock2 = records[1]; - const rootProfileServiceMock = new RootProfileService(); - rootProfileServiceMock.registerProvider(rootProfileProviderMock); - const dataSourceProfileServiceMock = new DataSourceProfileService(); - dataSourceProfileServiceMock.registerProvider(dataSourceProfileProviderMock); - const documentProfileServiceMock = new DocumentProfileService(); - documentProfileServiceMock.registerProvider(documentProfileProviderMock); + + if (shouldRegisterProviders) { + rootProfileServiceMock.registerProvider(rootProfileProviderMock); + dataSourceProfileServiceMock.registerProvider(dataSourceProfileProviderMock); + documentProfileServiceMock.registerProvider(documentProfileProviderMock); + } const profilesManagerMock = new ProfilesManager( rootProfileServiceMock, @@ -114,6 +116,9 @@ export const createContextAwarenessMocks = () => { rootProfileProviderMock, dataSourceProfileProviderMock, documentProfileProviderMock, + rootProfileServiceMock, + dataSourceProfileServiceMock, + documentProfileServiceMock, contextRecordMock, contextRecordMock2, profilesManagerMock, diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/index.ts new file mode 100644 index 00000000000000..032da55d4f6d0e --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { exampleDataSourceProfileProvider } from './profile'; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx new file mode 100644 index 00000000000000..080c2ffed222b9 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { EuiBadge } from '@elastic/eui'; +import type { DataTableRecord } from '@kbn/discover-utils'; +import { isOfAggregateQueryType } from '@kbn/es-query'; +import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { capitalize } from 'lodash'; +import React from 'react'; +import { DataSourceType, isDataSourceType } from '../../../../common/data_sources'; +import { DataSourceCategory, DataSourceProfileProvider } from '../../profiles'; + +export const exampleDataSourceProfileProvider: DataSourceProfileProvider = { + profileId: 'example-data-source-profile', + profile: { + getCellRenderers: (prev) => () => ({ + ...prev(), + 'log.level': (props) => { + const level = getFieldValue(props.row, 'log.level'); + + if (!level) { + return ( + + (None) + + ); + } + + const levelMap: Record = { + info: 'primary', + debug: 'default', + error: 'danger', + }; + + return ( + + {capitalize(level)} + + ); + }, + }), + }, + resolve: (params) => { + let indexPattern: string | undefined; + + if (isDataSourceType(params.dataSource, DataSourceType.Esql)) { + if (!isOfAggregateQueryType(params.query)) { + return { isMatch: false }; + } + + indexPattern = getIndexPatternFromESQLQuery(params.query.esql); + } else if (isDataSourceType(params.dataSource, DataSourceType.DataView) && params.dataView) { + indexPattern = params.dataView.getIndexPattern(); + } + + if (indexPattern !== 'my-example-logs') { + return { isMatch: false }; + } + + return { + isMatch: true, + context: { category: DataSourceCategory.Logs }, + }; + }, +}; + +const getFieldValue = (record: DataTableRecord, field: string) => { + const value = record.flattened[field]; + return Array.isArray(value) ? value[0] : value; +}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/index.ts new file mode 100644 index 00000000000000..dab5364d8af3ee --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { exampleDocumentProfileProvider } from './profile'; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts new file mode 100644 index 00000000000000..303efa103e327f --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { DataTableRecord } from '@kbn/discover-utils'; +import { DocumentProfileProvider, DocumentType } from '../../profiles'; + +export const exampleDocumentProfileProvider: DocumentProfileProvider = { + profileId: 'example-document-profile', + profile: {}, + resolve: (params) => { + if (getFieldValue(params.record, 'data_stream.type') !== 'logs') { + return { isMatch: false }; + } + + return { + isMatch: true, + context: { + type: DocumentType.Log, + }, + }; + }, +}; + +const getFieldValue = (record: DataTableRecord, field: string) => { + const value = record.flattened[field]; + return Array.isArray(value) ? value[0] : value; +}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/index.ts new file mode 100644 index 00000000000000..53f4cdc955db48 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { exampleRootProfileProvider } from './profile'; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/profile.tsx new file mode 100644 index 00000000000000..389059c5182179 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/profile.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 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 { EuiBadge } from '@elastic/eui'; +import type { DataTableRecord } from '@kbn/discover-utils'; +import React from 'react'; +import { RootProfileProvider, SolutionType } from '../../profiles'; + +export const exampleRootProfileProvider: RootProfileProvider = { + profileId: 'example-root-profile', + profile: { + getCellRenderers: (prev) => () => ({ + ...prev(), + '@timestamp': (props) => { + const timestamp = getFieldValue(props.row, '@timestamp'); + + return ( + + {timestamp} + + ); + }, + }), + }, + resolve: (params) => { + if (params.solutionNavId != null) { + return { isMatch: false }; + } + + return { isMatch: true, context: { solutionType: SolutionType.Default } }; + }, +}; + +const getFieldValue = (record: DataTableRecord, field: string) => { + const value = record.flattened[field]; + return Array.isArray(value) ? value[0] : value; +}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/index.ts new file mode 100644 index 00000000000000..1a5979f5a37f8c --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { registerProfileProviders } from './register_profile_providers'; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts index 7c1da0cef45cd4..2d03c9e35398af 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts @@ -8,7 +8,7 @@ import { DataTableRecord } from '@kbn/discover-utils'; import { DocumentProfileProvider, DocumentType } from '../../profiles'; -import { ProfileProviderServices } from '../../profiles/profile_provider_services'; +import { ProfileProviderServices } from '../profile_provider_services'; export const createLogDocumentProfileProvider = ( services: ProfileProviderServices diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts index 1ce42c6d1ffd12..e4a12aa9e4baf2 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts @@ -14,7 +14,7 @@ import { DataSourceProfileProvider, DataSourceProfileProviderParams, } from '../../profiles'; -import { ProfileProviderServices } from '../../profiles/profile_provider_services'; +import { ProfileProviderServices } from '../profile_provider_services'; export const createLogsDataSourceProfileProvider = ( services: ProfileProviderServices diff --git a/src/plugins/discover/public/context_awareness/profiles/profile_provider_services.ts b/src/plugins/discover/public/context_awareness/profile_providers/profile_provider_services.ts similarity index 100% rename from src/plugins/discover/public/context_awareness/profiles/profile_provider_services.ts rename to src/plugins/discover/public/context_awareness/profile_providers/profile_provider_services.ts diff --git a/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts new file mode 100644 index 00000000000000..c58726ecc1c11a --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts @@ -0,0 +1,117 @@ +/* + * 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 { createEsqlDataSource } from '../../../common/data_sources'; +import { createContextAwarenessMocks } from '../__mocks__'; +import { exampleDataSourceProfileProvider } from './example_data_source_profile'; +import { exampleDocumentProfileProvider } from './example_document_profile'; +import { exampleRootProfileProvider } from './example_root_pofile'; +import { + registerEnabledProfileProviders, + registerProfileProviders, +} from './register_profile_providers'; + +describe('registerEnabledProfileProviders', () => { + it('should register enabled profile providers', async () => { + const { rootProfileServiceMock, rootProfileProviderMock } = createContextAwarenessMocks({ + shouldRegisterProviders: false, + }); + registerEnabledProfileProviders({ + profileService: rootProfileServiceMock, + availableProviders: [rootProfileProviderMock], + enabledProfileIds: ['root-profile'], + }); + const context = await rootProfileServiceMock.resolve({ solutionNavId: null }); + expect(rootProfileServiceMock.getProfile(context)).toBe(rootProfileProviderMock.profile); + }); + + it('should not register disabled profile providers', async () => { + const { rootProfileServiceMock, rootProfileProviderMock } = createContextAwarenessMocks({ + shouldRegisterProviders: false, + }); + registerEnabledProfileProviders({ + profileService: rootProfileServiceMock, + availableProviders: [rootProfileProviderMock], + enabledProfileIds: [], + }); + const context = await rootProfileServiceMock.resolve({ solutionNavId: null }); + expect(rootProfileServiceMock.getProfile(context)).not.toBe(rootProfileProviderMock.profile); + }); +}); + +describe('registerProfileProviders', () => { + it('should register enabled experimental profile providers', async () => { + const { rootProfileServiceMock, dataSourceProfileServiceMock, documentProfileServiceMock } = + createContextAwarenessMocks({ + shouldRegisterProviders: false, + }); + registerProfileProviders({ + rootProfileService: rootProfileServiceMock, + dataSourceProfileService: dataSourceProfileServiceMock, + documentProfileService: documentProfileServiceMock, + experimentalProfileIds: [ + exampleRootProfileProvider.profileId, + exampleDataSourceProfileProvider.profileId, + exampleDocumentProfileProvider.profileId, + ], + }); + const rootContext = await rootProfileServiceMock.resolve({ solutionNavId: null }); + const dataSourceContext = await dataSourceProfileServiceMock.resolve({ + dataSource: createEsqlDataSource(), + query: { esql: 'from my-example-logs' }, + }); + const documentContext = documentProfileServiceMock.resolve({ + record: { + id: 'test', + flattened: { 'data_stream.type': 'logs' }, + raw: {}, + }, + }); + expect(rootProfileServiceMock.getProfile(rootContext)).toBe(exampleRootProfileProvider.profile); + expect(dataSourceProfileServiceMock.getProfile(dataSourceContext)).toBe( + exampleDataSourceProfileProvider.profile + ); + expect(documentProfileServiceMock.getProfile(documentContext)).toBe( + exampleDocumentProfileProvider.profile + ); + }); + + it('should not register disabled experimental profile providers', async () => { + const { rootProfileServiceMock, dataSourceProfileServiceMock, documentProfileServiceMock } = + createContextAwarenessMocks({ + shouldRegisterProviders: false, + }); + registerProfileProviders({ + rootProfileService: rootProfileServiceMock, + dataSourceProfileService: dataSourceProfileServiceMock, + documentProfileService: documentProfileServiceMock, + experimentalProfileIds: [], + }); + const rootContext = await rootProfileServiceMock.resolve({ solutionNavId: null }); + const dataSourceContext = await dataSourceProfileServiceMock.resolve({ + dataSource: createEsqlDataSource(), + query: { esql: 'from my-example-logs' }, + }); + const documentContext = documentProfileServiceMock.resolve({ + record: { + id: 'test', + flattened: { 'data_stream.type': 'logs' }, + raw: {}, + }, + }); + expect(rootProfileServiceMock.getProfile(rootContext)).not.toBe( + exampleRootProfileProvider.profile + ); + expect(dataSourceProfileServiceMock.getProfile(dataSourceContext)).not.toBe( + exampleDataSourceProfileProvider.profile + ); + expect(documentProfileServiceMock.getProfile(documentContext)).not.toBe( + exampleDocumentProfileProvider.profile + ); + }); +}); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.ts b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.ts new file mode 100644 index 00000000000000..1f4f2fbb7d931f --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { uniq } from 'lodash'; +import type { + DataSourceProfileService, + DocumentProfileService, + RootProfileService, +} from '../profiles'; +import type { BaseProfileProvider, BaseProfileService } from '../profile_service'; +import { exampleDataSourceProfileProvider } from './example_data_source_profile'; +import { exampleDocumentProfileProvider } from './example_document_profile'; +import { exampleRootProfileProvider } from './example_root_pofile'; +import { createLogsDataSourceProfileProvider } from './logs_data_source_profile'; +import { createLogDocumentProfileProvider } from './log_document_profile'; +import { createProfileProviderServices } from './profile_provider_services'; + +export const registerProfileProviders = ({ + rootProfileService, + dataSourceProfileService, + documentProfileService, + experimentalProfileIds, +}: { + rootProfileService: RootProfileService; + dataSourceProfileService: DataSourceProfileService; + documentProfileService: DocumentProfileService; + experimentalProfileIds: string[]; +}) => { + const providerServices = createProfileProviderServices(); + const logsDataSourceProfileProvider = createLogsDataSourceProfileProvider(providerServices); + const logsDocumentProfileProvider = createLogDocumentProfileProvider(providerServices); + const rootProfileProviders = [exampleRootProfileProvider]; + const dataSourceProfileProviders = [ + exampleDataSourceProfileProvider, + logsDataSourceProfileProvider, + ]; + const documentProfileProviders = [exampleDocumentProfileProvider, logsDocumentProfileProvider]; + const enabledProfileIds = uniq([ + logsDataSourceProfileProvider.profileId, + logsDocumentProfileProvider.profileId, + ...experimentalProfileIds, + ]); + + registerEnabledProfileProviders({ + profileService: rootProfileService, + availableProviders: rootProfileProviders, + enabledProfileIds, + }); + + registerEnabledProfileProviders({ + profileService: dataSourceProfileService, + availableProviders: dataSourceProfileProviders, + enabledProfileIds, + }); + + registerEnabledProfileProviders({ + profileService: documentProfileService, + availableProviders: documentProfileProviders, + enabledProfileIds, + }); +}; + +export const registerEnabledProfileProviders = < + TProvider extends BaseProfileProvider<{}>, + TService extends BaseProfileService +>({ + profileService, + availableProviders, + enabledProfileIds, +}: { + profileService: TService; + availableProviders: TProvider[]; + enabledProfileIds: string[]; +}) => { + for (const profile of availableProviders) { + if (enabledProfileIds.includes(profile.profileId)) { + profileService.registerProvider(profile); + } + } +}; diff --git a/src/plugins/discover/public/context_awareness/profile_service.ts b/src/plugins/discover/public/context_awareness/profile_service.ts index 2b43595761d195..efc143e222414b 100644 --- a/src/plugins/discover/public/context_awareness/profile_service.ts +++ b/src/plugins/discover/public/context_awareness/profile_service.ts @@ -15,38 +15,33 @@ export type ResolveProfileResult = | { isMatch: true; context: TContext } | { isMatch: false }; -export type ProfileProviderMode = 'sync' | 'async'; +export type ContextWithProfileId = TContext & { profileId: string }; -export interface ProfileProvider< - TProfile extends PartialProfile, - TParams, - TContext, - TMode extends ProfileProviderMode -> { +export interface BaseProfileProvider { profileId: string; profile: ComposableProfile; +} + +export interface ProfileProvider + extends BaseProfileProvider { + resolve: (params: TParams) => ResolveProfileResult; +} + +export interface AsyncProfileProvider + extends BaseProfileProvider { resolve: ( params: TParams - ) => TMode extends 'sync' - ? ResolveProfileResult - : ResolveProfileResult | Promise>; + ) => ResolveProfileResult | Promise>; } -export type ContextWithProfileId = TContext & { profileId: string }; - const EMPTY_PROFILE = {}; -abstract class BaseProfileService< - TProfile extends PartialProfile, - TParams, - TContext, - TMode extends ProfileProviderMode -> { - protected readonly providers: Array> = []; +export abstract class BaseProfileService, TContext> { + protected readonly providers: TProvider[] = []; protected constructor(public readonly defaultContext: ContextWithProfileId) {} - public registerProvider(provider: ProfileProvider) { + public registerProvider(provider: TProvider) { this.providers.push(provider); } @@ -54,19 +49,13 @@ abstract class BaseProfileService< const provider = this.providers.find((current) => current.profileId === context.profileId); return provider?.profile ?? EMPTY_PROFILE; } - - public abstract resolve( - params: TParams - ): TMode extends 'sync' - ? ContextWithProfileId - : Promise>; } export class ProfileService< TProfile extends PartialProfile, TParams, TContext -> extends BaseProfileService { +> extends BaseProfileService, TContext> { public resolve(params: TParams) { for (const provider of this.providers) { const result = provider.resolve(params); @@ -87,7 +76,7 @@ export class AsyncProfileService< TProfile extends PartialProfile, TParams, TContext -> extends BaseProfileService { +> extends BaseProfileService, TContext> { public async resolve(params: TParams) { for (const provider of this.providers) { const result = await provider.resolve(params); diff --git a/src/plugins/discover/public/context_awareness/profiles/data_source_profile.ts b/src/plugins/discover/public/context_awareness/profiles/data_source_profile.ts index f616fef913259b..1dbb3c20d8b510 100644 --- a/src/plugins/discover/public/context_awareness/profiles/data_source_profile.ts +++ b/src/plugins/discover/public/context_awareness/profiles/data_source_profile.ts @@ -9,7 +9,7 @@ import type { DataView } from '@kbn/data-views-plugin/common'; import type { AggregateQuery, Query } from '@kbn/es-query'; import type { DiscoverDataSource } from '../../../common/data_sources'; -import { AsyncProfileService } from '../profile_service'; +import { AsyncProfileProvider, AsyncProfileService } from '../profile_service'; import { Profile } from '../types'; export enum DataSourceCategory { @@ -17,6 +17,8 @@ export enum DataSourceCategory { Default = 'default', } +export type DataSourceProfile = Profile; + export interface DataSourceProfileProviderParams { dataSource?: DiscoverDataSource; dataView?: DataView; @@ -27,7 +29,11 @@ export interface DataSourceContext { category: DataSourceCategory; } -export type DataSourceProfile = Profile; +export type DataSourceProfileProvider = AsyncProfileProvider< + DataSourceProfile, + DataSourceProfileProviderParams, + DataSourceContext +>; export class DataSourceProfileService extends AsyncProfileService< DataSourceProfile, @@ -41,5 +47,3 @@ export class DataSourceProfileService extends AsyncProfileService< }); } } - -export type DataSourceProfileProvider = Parameters[0]; diff --git a/src/plugins/discover/public/context_awareness/profiles/document_profile.ts b/src/plugins/discover/public/context_awareness/profiles/document_profile.ts index 70b134da452e47..c6fd19b8f2014d 100644 --- a/src/plugins/discover/public/context_awareness/profiles/document_profile.ts +++ b/src/plugins/discover/public/context_awareness/profiles/document_profile.ts @@ -8,13 +8,15 @@ import type { DataTableRecord } from '@kbn/discover-utils'; import type { Profile } from '../types'; -import { ProfileService } from '../profile_service'; +import { ProfileProvider, ProfileService } from '../profile_service'; export enum DocumentType { Log = 'log', Default = 'default', } +export type DocumentProfile = Omit; + export interface DocumentProfileProviderParams { record: DataTableRecord; } @@ -23,7 +25,11 @@ export interface DocumentContext { type: DocumentType; } -export type DocumentProfile = Omit; +export type DocumentProfileProvider = ProfileProvider< + DocumentProfile, + DocumentProfileProviderParams, + DocumentContext +>; export class DocumentProfileService extends ProfileService< DocumentProfile, @@ -37,5 +43,3 @@ export class DocumentProfileService extends ProfileService< }); } } - -export type DocumentProfileProvider = Parameters[0]; diff --git a/src/plugins/discover/public/context_awareness/profiles/example_profiles.tsx b/src/plugins/discover/public/context_awareness/profiles/example_profiles.tsx deleted file mode 100644 index 3835337b253049..00000000000000 --- a/src/plugins/discover/public/context_awareness/profiles/example_profiles.tsx +++ /dev/null @@ -1,123 +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 { EuiBadge } from '@elastic/eui'; -import { - DataTableRecord, - getMessageFieldWithFallbacks, - LogDocumentOverview, -} from '@kbn/discover-utils'; -import { isOfAggregateQueryType } from '@kbn/es-query'; -import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; -import { euiThemeVars } from '@kbn/ui-theme'; -import { capitalize } from 'lodash'; -import React from 'react'; -import { DataSourceType, isDataSourceType } from '../../../common/data_sources'; -import { DataSourceCategory, DataSourceProfileProvider } from './data_source_profile'; -import { DocumentProfileProvider, DocumentType } from './document_profile'; -import { RootProfileProvider, SolutionType } from './root_profile'; - -export const o11yRootProfileProvider: RootProfileProvider = { - profileId: 'o11y-root-profile', - profile: {}, - resolve: (params) => { - if (params.solutionNavId === 'oblt') { - return { - isMatch: true, - context: { - solutionType: SolutionType.Observability, - }, - }; - } - - return { isMatch: false }; - }, -}; - -export const logsDataSourceProfileProvider: DataSourceProfileProvider = { - profileId: 'logs-data-source-profile', - profile: { - getCellRenderers: (prev) => () => ({ - ...prev(), - '@timestamp': (props) => { - const timestamp = getFieldValue(props.row, '@timestamp'); - return ( - - {timestamp} - - ); - }, - 'log.level': (props) => { - const level = getFieldValue(props.row, 'log.level'); - if (!level) { - return (None); - } - const levelMap: Record = { - info: 'primary', - debug: 'default', - error: 'danger', - }; - return ( - - {capitalize(level)} - - ); - }, - message: (props) => { - const { value } = getMessageFieldWithFallbacks( - props.row.flattened as unknown as LogDocumentOverview - ); - return value || (None); - }, - }), - }, - resolve: (params) => { - let indices: string[] = []; - - if (isDataSourceType(params.dataSource, DataSourceType.Esql)) { - if (!isOfAggregateQueryType(params.query)) { - return { isMatch: false }; - } - - indices = getIndexPatternFromESQLQuery(params.query.esql).split(','); - } else if (isDataSourceType(params.dataSource, DataSourceType.DataView) && params.dataView) { - indices = params.dataView.getIndexPattern().split(','); - } - - if (indices.every((index) => index.startsWith('logs-'))) { - return { - isMatch: true, - context: { category: DataSourceCategory.Logs }, - }; - } - - return { isMatch: false }; - }, -}; - -export const logDocumentProfileProvider: DocumentProfileProvider = { - profileId: 'log-document-profile', - profile: {}, - resolve: (params) => { - if (getFieldValue(params.record, 'data_stream.type') === 'logs') { - return { - isMatch: true, - context: { - type: DocumentType.Log, - }, - }; - } - - return { isMatch: false }; - }, -}; - -const getFieldValue = (record: DataTableRecord, field: string) => { - const value = record.flattened[field]; - return Array.isArray(value) ? value[0] : value; -}; diff --git a/src/plugins/discover/public/context_awareness/profiles/root_profile.ts b/src/plugins/discover/public/context_awareness/profiles/root_profile.ts index 42497fe680c5cc..77bf9d9d63b0b6 100644 --- a/src/plugins/discover/public/context_awareness/profiles/root_profile.ts +++ b/src/plugins/discover/public/context_awareness/profiles/root_profile.ts @@ -7,7 +7,7 @@ */ import type { Profile } from '../types'; -import { AsyncProfileService } from '../profile_service'; +import { AsyncProfileProvider, AsyncProfileService } from '../profile_service'; export enum SolutionType { Observability = 'oblt', @@ -16,6 +16,8 @@ export enum SolutionType { Default = 'default', } +export type RootProfile = Profile; + export interface RootProfileProviderParams { solutionNavId?: string | null; } @@ -24,7 +26,11 @@ export interface RootContext { solutionType: SolutionType; } -export type RootProfile = Profile; +export type RootProfileProvider = AsyncProfileProvider< + RootProfile, + RootProfileProviderParams, + RootContext +>; export class RootProfileService extends AsyncProfileService< RootProfile, @@ -38,5 +44,3 @@ export class RootProfileService extends AsyncProfileService< }); } } - -export type RootProfileProvider = Parameters[0]; diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index 4f1ae2a32634e4..78da5820f1ddbb 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -21,6 +21,7 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; import { ENABLE_ESQL } from '@kbn/esql-utils'; import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import { TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; +import { once } from 'lodash'; import { PLUGIN_ID } from '../common'; import { registerFeature } from './register_feature'; import { buildServices, UrlTracker } from './build_services'; @@ -56,10 +57,7 @@ import { ProfilesManager, RootProfileService, } from './context_awareness'; -import { createProfileProviderServices } from './context_awareness/profiles/profile_provider_services'; import { DiscoverSetup, DiscoverSetupPlugins, DiscoverStart, DiscoverStartPlugins } from './types'; -import { createLogsDataSourceProfileProvider } from './context_awareness/profile_providers/logs_data_source_profile'; -import { createLogDocumentProfileProvider } from './context_awareness/profile_providers/log_document_profile'; /** * Contains Discover, one of the oldest parts of Kibana @@ -68,16 +66,11 @@ import { createLogDocumentProfileProvider } from './context_awareness/profile_pr export class DiscoverPlugin implements Plugin { - private readonly rootProfileService = new RootProfileService(); - private readonly dataSourceProfileService = new DataSourceProfileService(); - private readonly documentProfileService = new DocumentProfileService(); private readonly appStateUpdater = new BehaviorSubject(() => ({})); private readonly historyService = new HistoryService(); private readonly inlineTopNav: Map = new Map([[null, defaultCustomizationContext.inlineTopNav]]); - private readonly experimentalFeatures: ExperimentalFeatures = { - ruleFormV2Enabled: false, - }; + private readonly experimentalFeatures: ExperimentalFeatures; private scopedHistory?: ScopedHistory; private urlTracker?: UrlTracker; @@ -87,8 +80,12 @@ export class DiscoverPlugin private singleDocLocator?: DiscoverSingleDocLocator; constructor(private readonly initializerContext: PluginInitializerContext) { - this.experimentalFeatures = - initializerContext.config.get().experimental ?? this.experimentalFeatures; + const experimental = this.initializerContext.config.get().experimental; + + this.experimentalFeatures = { + ruleFormV2Enabled: experimental?.ruleFormV2Enabled ?? false, + enabledProfiles: experimental?.enabledProfiles ?? [], + }; } setup( @@ -184,7 +181,7 @@ export class DiscoverPlugin history: this.historyService.getHistory(), scopedHistory: this.scopedHistory, urlTracker: this.urlTracker!, - profilesManager: this.createProfilesManager(), + profilesManager: await this.createProfilesManager(), setHeaderActionMenu: params.setHeaderActionMenu, }); @@ -267,8 +264,6 @@ export class DiscoverPlugin } start(core: CoreStart, plugins: DiscoverStartPlugins): DiscoverStart { - this.registerProfiles(); - const viewSavedSearchAction = new ViewSavedSearchAction(core.application, this.locator!); plugins.uiActions.addTriggerAction('CONTEXT_MENU_TRIGGER', viewSavedSearchAction); @@ -304,22 +299,31 @@ export class DiscoverPlugin } } - private registerProfiles() { - const providerServices = createProfileProviderServices(); + private createProfileServices = once(async () => { + const { registerProfileProviders } = await import('./context_awareness/profile_providers'); + const rootProfileService = new RootProfileService(); + const dataSourceProfileService = new DataSourceProfileService(); + const documentProfileService = new DocumentProfileService(); + const experimentalProfileIds = this.experimentalFeatures.enabledProfiles ?? []; + + registerProfileProviders({ + rootProfileService, + dataSourceProfileService, + documentProfileService, + experimentalProfileIds, + }); - this.dataSourceProfileService.registerProvider( - createLogsDataSourceProfileProvider(providerServices) - ); - this.documentProfileService.registerProvider( - createLogDocumentProfileProvider(providerServices) - ); - } + return { rootProfileService, dataSourceProfileService, documentProfileService }; + }); + + private async createProfilesManager() { + const { rootProfileService, dataSourceProfileService, documentProfileService } = + await this.createProfileServices(); - private createProfilesManager() { return new ProfilesManager( - this.rootProfileService, - this.dataSourceProfileService, - this.documentProfileService + rootProfileService, + dataSourceProfileService, + documentProfileService ); } @@ -334,7 +338,7 @@ export class DiscoverPlugin private getDiscoverServices = ( core: CoreStart, plugins: DiscoverStartPlugins, - profilesManager = this.createProfilesManager() + profilesManager: ProfilesManager ) => { return buildServices({ core, @@ -360,7 +364,8 @@ export class DiscoverPlugin const getDiscoverServicesInternal = async () => { const [coreStart, deps] = await core.getStartServices(); - return this.getDiscoverServices(coreStart, deps); + const profilesManager = await this.createProfilesManager(); + return this.getDiscoverServices(coreStart, deps, profilesManager); }; const factory = new SearchEmbeddableFactory(getStartServices, getDiscoverServicesInternal); diff --git a/test/functional/apps/discover/context_awareness/_data_source_profile.ts b/test/functional/apps/discover/context_awareness/_data_source_profile.ts new file mode 100644 index 00000000000000..d203f33c887e8a --- /dev/null +++ b/test/functional/apps/discover/context_awareness/_data_source_profile.ts @@ -0,0 +1,97 @@ +/* + * 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 kbnRison from '@kbn/rison'; +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'timePicker', 'discover', 'unifiedFieldList']); + const testSubjects = getService('testSubjects'); + const dataViews = getService('dataViews'); + + describe('data source profile', () => { + describe('ES|QL mode', () => { + describe('cell renderers', () => { + it('should render custom @timestamp but not custom log.level', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-* | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@timestamp'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp'); + expect(timestamps).to.have.length(6); + expect(await timestamps[0].getVisibleText()).to.be('2024-06-10T16:30:00.000Z'); + expect(await timestamps[5].getVisibleText()).to.be('2024-06-10T14:00:00.000Z'); + const logLevels = await testSubjects.findAll('exampleDataSourceProfileLogLevel', 2500); + expect(logLevels).to.have.length(0); + }); + + it('should render custom @timestamp and custom log.level', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-logs | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@timestamp'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp'); + expect(timestamps).to.have.length(3); + expect(await timestamps[0].getVisibleText()).to.be('2024-06-10T16:00:00.000Z'); + expect(await timestamps[2].getVisibleText()).to.be('2024-06-10T14:00:00.000Z'); + const logLevels = await testSubjects.findAll('exampleDataSourceProfileLogLevel'); + expect(logLevels).to.have.length(3); + expect(await logLevels[0].getVisibleText()).to.be('Debug'); + expect(await logLevels[2].getVisibleText()).to.be('Info'); + }); + }); + }); + + describe('data view mode', () => { + describe('cell renderers', () => { + it('should render custom @timestamp but not custom log.level', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-*'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@timestamp'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp'); + expect(timestamps).to.have.length(6); + expect(await timestamps[0].getVisibleText()).to.be('2024-06-10T16:30:00.000Z'); + expect(await timestamps[5].getVisibleText()).to.be('2024-06-10T14:00:00.000Z'); + const logLevels = await testSubjects.findAll('exampleDataSourceProfileLogLevel', 2500); + expect(logLevels).to.have.length(0); + }); + + it('should render custom @timestamp and custom log.level', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-logs'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@timestamp'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp'); + expect(timestamps).to.have.length(3); + expect(await timestamps[0].getVisibleText()).to.be('2024-06-10T16:00:00.000Z'); + expect(await timestamps[2].getVisibleText()).to.be('2024-06-10T14:00:00.000Z'); + const logLevels = await testSubjects.findAll('exampleDataSourceProfileLogLevel'); + expect(logLevels).to.have.length(3); + expect(await logLevels[0].getVisibleText()).to.be('Debug'); + expect(await logLevels[2].getVisibleText()).to.be('Info'); + }); + }); + }); + }); +} diff --git a/test/functional/apps/discover/context_awareness/_root_profile.ts b/test/functional/apps/discover/context_awareness/_root_profile.ts new file mode 100644 index 00000000000000..c0bb4885699f87 --- /dev/null +++ b/test/functional/apps/discover/context_awareness/_root_profile.ts @@ -0,0 +1,52 @@ +/* + * 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 kbnRison from '@kbn/rison'; +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'timePicker', 'discover']); + const testSubjects = getService('testSubjects'); + const dataViews = getService('dataViews'); + + describe('root profile', () => { + describe('ES|QL mode', () => { + describe('cell renderers', () => { + it('should render custom @timestamp', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-* | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp'); + expect(timestamps).to.have.length(6); + expect(await timestamps[0].getVisibleText()).to.be('2024-06-10T16:30:00.000Z'); + expect(await timestamps[5].getVisibleText()).to.be('2024-06-10T14:00:00.000Z'); + }); + }); + }); + + describe('data view mode', () => { + describe('cell renderers', () => { + it('should render custom @timestamp', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-*'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp'); + expect(timestamps).to.have.length(6); + expect(await timestamps[0].getVisibleText()).to.be('2024-06-10T16:30:00.000Z'); + expect(await timestamps[5].getVisibleText()).to.be('2024-06-10T14:00:00.000Z'); + }); + }); + }); + }); +} diff --git a/test/functional/apps/discover/context_awareness/config.ts b/test/functional/apps/discover/context_awareness/config.ts new file mode 100644 index 00000000000000..c8e43a6bb2c9d5 --- /dev/null +++ b/test/functional/apps/discover/context_awareness/config.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + const baseConfig = functionalConfig.getAll(); + + return { + ...baseConfig, + testFiles: [require.resolve('.')], + kbnTestServer: { + ...baseConfig.kbnTestServer, + serverArgs: [ + ...baseConfig.kbnTestServer.serverArgs, + '--discover.experimental.enabledProfiles=["example-root-profile","example-data-source-profile","example-document-profile"]', + ], + }, + }; +} diff --git a/test/functional/apps/discover/context_awareness/index.ts b/test/functional/apps/discover/context_awareness/index.ts new file mode 100644 index 00000000000000..f280024ec7c80e --- /dev/null +++ b/test/functional/apps/discover/context_awareness/index.ts @@ -0,0 +1,39 @@ +/* + * 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 { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, getPageObjects, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['timePicker']); + const from = '2024-06-10T14:00:00.000Z'; + const to = '2024-06-10T16:30:00.000Z'; + + describe('discover/context_awareness', () => { + before(async () => { + await esArchiver.load('test/functional/fixtures/es_archiver/discover/context_awareness'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/discover/context_awareness' + ); + await kibanaServer.uiSettings.update({ + 'timepicker:timeDefaults': `{ "from": "${from}", "to": "${to}"}`, + }); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/discover/context_awareness'); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/discover/context_awareness' + ); + await PageObjects.timePicker.resetDefaultAbsoluteRangeViaUiSettings(); + }); + + loadTestFile(require.resolve('./_root_profile')); + loadTestFile(require.resolve('./_data_source_profile')); + }); +} diff --git a/test/functional/fixtures/es_archiver/discover/context_awareness/data.json.gz b/test/functional/fixtures/es_archiver/discover/context_awareness/data.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..cd1f670958d7d47b36a6868efc537ec09bb76939 GIT binary patch literal 351 zcmV-l0igaLiwFP!000026Sb2;Z-Ous$M1ZKm!1cyC@gZ?=G@d66BDzsU6x8KW1%gh z#psOR-IQpQi`x`PIMDZhEx#X+jRk=8I%6mRL}i3-%)*kSg<08H001bVrW#JB{m1P7 zVe$MUUV5#$KNyKJZW4mBl?m~+%~phGDYH`Tr^Xh5T(!Oy~lyIi=B)ahTY5&nm^$-BWmP}}e7CF(06es}K_i%Y# x4E{E$f`7M%?S{bpI>9l { + describe('ES|QL mode', () => { + describe('cell renderers', () => { + it('should not render custom @timestamp or log.level', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-* | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@timestamp'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp', 2500); + expect(timestamps).to.have.length(0); + const logLevels = await testSubjects.findAll('exampleDataSourceProfileLogLevel', 2500); + expect(logLevels).to.have.length(0); + }); + + it('should not render custom @timestamp but should render custom log.level', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-logs | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@timestamp'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp', 2500); + expect(timestamps).to.have.length(0); + const logLevels = await testSubjects.findAll('exampleDataSourceProfileLogLevel'); + expect(logLevels).to.have.length(3); + expect(await logLevels[0].getVisibleText()).to.be('Debug'); + expect(await logLevels[2].getVisibleText()).to.be('Info'); + }); + }); + }); + + describe('data view mode', () => { + describe('cell renderers', () => { + it('should not render custom @timestamp or log.level', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-*'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@timestamp'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp', 2500); + expect(timestamps).to.have.length(0); + const logLevels = await testSubjects.findAll('exampleDataSourceProfileLogLevel', 2500); + expect(logLevels).to.have.length(0); + }); + + it('should not render custom @timestamp but should render custom log.level', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-logs'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('@timestamp'); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp', 2500); + expect(timestamps).to.have.length(0); + const logLevels = await testSubjects.findAll('exampleDataSourceProfileLogLevel'); + expect(logLevels).to.have.length(3); + expect(await logLevels[0].getVisibleText()).to.be('Debug'); + expect(await logLevels[2].getVisibleText()).to.be('Info'); + }); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/_root_profile.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/_root_profile.ts new file mode 100644 index 00000000000000..649d0a67ee22fb --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/_root_profile.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import kbnRison from '@kbn/rison'; +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'timePicker', 'discover']); + const testSubjects = getService('testSubjects'); + const dataViews = getService('dataViews'); + + describe('root profile', () => { + describe('ES|QL mode', () => { + describe('cell renderers', () => { + it('should not render custom @timestamp', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-* | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp', 2500); + expect(timestamps).to.have.length(0); + }); + }); + }); + + describe('data view mode', () => { + describe('cell renderers', () => { + it('should not render custom @timestamp', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-*'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + const timestamps = await testSubjects.findAll('exampleRootProfileTimestamp', 2500); + expect(timestamps).to.have.length(0); + }); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts new file mode 100644 index 00000000000000..e6e128e4b6b598 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['timePicker', 'svlCommonPage']); + const from = '2024-06-10T14:00:00.000Z'; + const to = '2024-06-10T16:30:00.000Z'; + + describe('discover/context_awareness', () => { + before(async () => { + await esArchiver.load('test/functional/fixtures/es_archiver/discover/context_awareness'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/discover/context_awareness' + ); + await kibanaServer.uiSettings.update({ + 'timepicker:timeDefaults': `{ "from": "${from}", "to": "${to}"}`, + }); + await PageObjects.svlCommonPage.login(); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/discover/context_awareness'); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/discover/context_awareness' + ); + await PageObjects.timePicker.resetDefaultAbsoluteRangeViaUiSettings(); + }); + + loadTestFile(require.resolve('./_root_profile')); + loadTestFile(require.resolve('./_data_source_profile')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.context_awareness.ts b/x-pack/test_serverless/functional/test_suites/observability/config.context_awareness.ts new file mode 100644 index 00000000000000..76362cc111e6f0 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/config.context_awareness.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../config.base'; + +export default createTestConfig({ + serverlessProject: 'oblt', + testFiles: [require.resolve('../common/discover/context_awareness')], + junit: { + reportName: 'Serverless Observability Discover Context Awareness Functional Tests', + }, + kbnServerArgs: [ + '--discover.experimental.enabledProfiles=["example-root-profile","example-data-source-profile","example-document-profile"]', + ], + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml + esServerArgs: ['xpack.ml.dfa.enabled=false'], +}); diff --git a/x-pack/test_serverless/functional/test_suites/search/config.context_awareness.ts b/x-pack/test_serverless/functional/test_suites/search/config.context_awareness.ts new file mode 100644 index 00000000000000..7b608c29c9f3a5 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/config.context_awareness.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../config.base'; + +export default createTestConfig({ + serverlessProject: 'es', + testFiles: [require.resolve('../common/discover/context_awareness')], + junit: { + reportName: 'Serverless Search Discover Context Awareness Functional Tests', + }, + kbnServerArgs: [ + '--discover.experimental.enabledProfiles=["example-root-profile","example-data-source-profile","example-document-profile"]', + ], + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml + esServerArgs: ['xpack.ml.dfa.enabled=false'], +}); diff --git a/x-pack/test_serverless/functional/test_suites/security/config.context_awareness.ts b/x-pack/test_serverless/functional/test_suites/security/config.context_awareness.ts new file mode 100644 index 00000000000000..6276922df83f4c --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/config.context_awareness.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../config.base'; + +export default createTestConfig({ + serverlessProject: 'security', + testFiles: [require.resolve('../common/discover/context_awareness')], + junit: { + reportName: 'Serverless Security Discover Context Awareness Functional Tests', + }, + kbnServerArgs: [ + '--discover.experimental.enabledProfiles=["example-root-profile","example-data-source-profile","example-document-profile"]', + ], + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml + esServerArgs: ['xpack.ml.dfa.enabled=false'], +}); From 2f4997cbfebdd6d69937d00f7f1e6e59e98f0ca6 Mon Sep 17 00:00:00 2001 From: Marta Bondyra <4283304+mbondyra@users.noreply.github.com> Date: Wed, 19 Jun 2024 21:04:07 +0200 Subject: [PATCH 105/123] [Lens] Legend Statistics feature (#182357) ## Summary Fixes https://github.com/elastic/kibana/issues/183887 Screenshot 2024-06-09 at 21 11 33 Screenshot 2024-06-09 at 21 11 38 - [x] popover width = 500 px - [x] new combobox legend values component added - [x] switch show value removed - [x] location and alignment is in a single for row - [x] auto legend width option to allow users to have the legend automatically size based its contents - not there yet - [x] no limit imposed of the number of values - [x] when a value is selected, list or table appears - [x] when the list is selected, label truncations is not offered and legend items should be forced to have truncation on and clamped to a single line. - [x] adds telemetry too - adds events on save if the legend statistics change: `lens_legend_stats`- triggered if any stats is in legend `lens_legend_stats_${TYPE}` - triggered for specific types, if user has 2 statistics (eg. AVG and MIN) two events are triggered. and counting how many they use `lens_legend_stats_amount_1` `lens_legend_stats_amount_2` `lens_legend_stats_amount_3` `lens_legend_stats_amount_4_7` `lens_legend_stats_amount_above_8` --------- Co-authored-by: Nick Partridge Co-authored-by: Marco Vettorello --- .../visualization_types/xy_chart.ts | 4 +- .../waffle_vis_function.test.ts | 8 +- .../public/__stories__/shared/arg_types.ts | 5 +- .../expression_partition_vis/public/mocks.ts | 4 +- .../expression_functions/legend_config.ts | 22 +- .../common/types/expression_functions.ts | 7 +- .../public/components/xy_chart.test.tsx | 9 +- .../public/components/xy_chart.tsx | 23 +- .../configurations/index.test.ts | 4 +- .../convert_to_lens/configurations/index.ts | 6 +- .../convert_to_lens/configurations/index.ts | 5 +- src/plugins/vis_types/xy/public/to_ast.ts | 5 +- .../visualizations/common/constants.ts | 33 ++- .../convert_to_lens/types/configurations.ts | 2 +- src/plugins/visualizations/common/index.ts | 5 +- .../axis/title/axis_title_settings.tsx | 101 -------- ...st.tsx => toolbar_title_settings.test.tsx} | 28 +- .../axis/title/toolbar_title_settings.tsx | 107 ++++++++ .../lens/public/shared_components/index.ts | 2 +- .../legend/layout/columns_number_setting.tsx | 8 +- .../legend/legend_settings_popover.test.tsx | 26 +- .../legend/legend_settings_popover.tsx | 243 ++++++++++++------ .../location/legend_location_settings.tsx | 4 +- .../legend/size/legend_size_settings.tsx | 2 +- .../public/shared_components/vis_label.tsx | 5 +- .../heatmap/toolbar_component.tsx | 18 +- .../partition/partition_charts_meta.ts | 5 +- .../visualizations/partition/persistence.tsx | 4 +- .../partition/render_helpers.test.ts | 18 +- .../partition/render_helpers.ts | 4 +- .../visualizations/partition/toolbar.tsx | 25 +- .../partition/visualization.test.ts | 4 +- .../xy/legend_stats_telemetry_helpers.test.ts | 113 ++++++++ .../xy/legend_stats_telemetry_helpers.ts | 49 ++++ .../public/visualizations/xy/persistence.ts | 4 +- .../public/visualizations/xy/to_expression.ts | 3 + .../visualizations/xy/visualization.test.tsx | 5 +- .../visualizations/xy/visualization.tsx | 16 +- .../axis_settings_popover.test.tsx | 2 +- .../xy_config_panel/axis_settings_popover.tsx | 18 +- .../xy/xy_config_panel/index.tsx | 225 ++++++++++++++-- .../translations/translations/fr-FR.json | 3 +- .../translations/translations/ja-JP.json | 3 +- .../translations/translations/zh-CN.json | 3 +- .../apps/lens/group6/legend_statistics.ts | 103 +++++--- .../test/functional/page_objects/lens_page.ts | 7 +- 46 files changed, 953 insertions(+), 347 deletions(-) delete mode 100644 x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.tsx rename x-pack/plugins/lens/public/shared_components/axis/title/{axis_title_settings.test.tsx => toolbar_title_settings.test.tsx} (80%) create mode 100644 x-pack/plugins/lens/public/shared_components/axis/title/toolbar_title_settings.tsx create mode 100644 x-pack/plugins/lens/public/visualizations/xy/legend_stats_telemetry_helpers.test.ts create mode 100644 x-pack/plugins/lens/public/visualizations/xy/legend_stats_telemetry_helpers.ts diff --git a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts index a992a97a23e4b9..60891ea0b1c10c 100644 --- a/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts +++ b/packages/kbn-lens-embeddable-utils/attribute_builder/visualization_types/xy_chart.ts @@ -17,7 +17,7 @@ import type { import type { DataView } from '@kbn/data-views-plugin/public'; import type { SavedObjectReference } from '@kbn/core/server'; import { AxesSettingsConfig } from '@kbn/visualizations-plugin/common'; -import type { XYLegendValue } from '@kbn/visualizations-plugin/common/constants'; +import { LegendValue } from '@elastic/charts'; import type { Chart, ChartConfig, ChartLayer } from '../types'; import { DEFAULT_LAYER_ID } from '../utils'; import { XY_ID } from './constants'; @@ -131,7 +131,7 @@ export const getXYVisualizationState = ( isVisible: false, position: 'right', showSingleSeries: false, - legendStats: ['currentAndLastValue' as XYLegendValue.CurrentAndLastValue], + legendStats: [LegendValue.CurrentAndLastValue], }, valueLabels: 'show', yLeftScale: 'linear', diff --git a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.test.ts b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.test.ts index e5a14a37e0ffb9..f3f4a3c9a144f7 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.test.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/common/expression_functions/waffle_vis_function.test.ts @@ -13,14 +13,12 @@ import { ValueFormats, LegendDisplay, } from '../types/expression_renderers'; -import { - ExpressionValueVisDimension, - PartitionLegendValue, -} from '@kbn/visualizations-plugin/common'; +import { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common'; import { Datatable } from '@kbn/expressions-plugin/common/expression_types/specs'; import { waffleVisFunction } from './waffle_vis_function'; import { PARTITION_LABELS_VALUE, PARTITION_VIS_RENDERER_NAME } from '../constants'; import { ExecutionContext } from '@kbn/expressions-plugin/common'; +import { LegendValue } from '@elastic/charts'; describe('interpreter/functions#waffleVis', () => { const fn = functionWrapper(waffleVisFunction()); @@ -37,7 +35,7 @@ describe('interpreter/functions#waffleVis', () => { const visConfig: WaffleVisConfig = { addTooltip: true, - legendStats: [PartitionLegendValue.Value], + legendStats: [LegendValue.Value], metricsToLabels: JSON.stringify({}), legendDisplay: LegendDisplay.SHOW, legendPosition: 'right', diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/__stories__/shared/arg_types.ts b/src/plugins/chart_expressions/expression_partition_vis/public/__stories__/shared/arg_types.ts index 314eb3369b61de..a35e9b09f56627 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/__stories__/shared/arg_types.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/__stories__/shared/arg_types.ts @@ -6,9 +6,8 @@ * Side Public License, v 1. */ -import { Position } from '@elastic/charts'; +import { LegendValue, Position } from '@elastic/charts'; import { ArgTypes } from '@storybook/addons'; -import { PartitionLegendValue } from '@kbn/visualizations-plugin/common/constants'; import { EmptySizeRatios, LegendDisplay } from '../../../common'; import { ChartTypes } from '../../../common/types'; @@ -212,7 +211,7 @@ export const waffleArgTypes: ArgTypes = { description: 'Legend stats', type: { name: 'string', required: false }, table: { type: { summary: 'string' }, defaultValue: { summary: undefined } }, - options: [PartitionLegendValue.Value], + options: [LegendValue.Value], control: { type: 'select' }, }, }; diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/mocks.ts b/src/plugins/chart_expressions/expression_partition_vis/public/mocks.ts index 4f48c03f7f9155..faea42ddc0b136 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/mocks.ts +++ b/src/plugins/chart_expressions/expression_partition_vis/public/mocks.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import { LegendValue } from '@elastic/charts'; import { Datatable } from '@kbn/expressions-plugin/public'; -import { PartitionLegendValue } from '@kbn/visualizations-plugin/common/constants'; import { BucketColumns, PartitionVisParams, @@ -382,6 +382,6 @@ export const createMockWaffleParams = (): PartitionVisParams => { }, ], }, - legendStats: [PartitionLegendValue.Value], + legendStats: [LegendValue.Value], }; }; diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/legend_config.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/legend_config.ts index e83db93c914af6..c9e524dcae8186 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/legend_config.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/legend_config.ts @@ -8,7 +8,7 @@ import { HorizontalAlignment, Position, VerticalAlignment } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; -import { LegendSize } from '@kbn/visualizations-plugin/common/constants'; +import { LegendLayout, LegendSize } from '@kbn/visualizations-plugin/common/constants'; import { LEGEND_CONFIG } from '../constants'; import { LegendConfigFn } from '../types'; @@ -106,6 +106,26 @@ export const legendConfigFunction: LegendConfigFn = { defaultMessage: 'Specifies the legend stats.', }), }, + title: { + types: ['string'], + help: i18n.translate('expressionXY.legendConfig.title.help', { + defaultMessage: 'Specifies the legend title.', + }), + }, + isTitleVisible: { + types: ['boolean'], + help: i18n.translate('expressionXY.legendConfig.isTitleVisible.help', { + defaultMessage: 'Specifies if the legend title is visible.', + }), + }, + layout: { + types: ['string'], + help: i18n.translate('expressionXY.legendConfig.legendLayout.help', { + defaultMessage: 'Specifies the legend layout.', + }), + options: [LegendLayout.Table, LegendLayout.List], + strict: true, + }, }, async fn(input, args, handlers) { const { legendConfigFn } = await import('./legend_config_fn'); diff --git a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts index a93a8510d4506c..dd4c0acbd22fc8 100644 --- a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts @@ -16,8 +16,9 @@ import type { } from '@kbn/expressions-plugin/common'; import { LegendSize, - ExpressionValueVisDimension, XYLegendValue, + LegendLayout, + ExpressionValueVisDimension, } from '@kbn/visualizations-plugin/common'; import { EventAnnotationOutput } from '@kbn/event-annotation-plugin/common'; @@ -220,7 +221,11 @@ export interface LegendConfig { /** * metrics to display in the legend */ + legendStats?: XYLegendValue[]; + layout?: LegendLayout; + title?: string; + isTitleVisible?: boolean; } // Arguments to XY chart expression, with computed properties diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx index da0997b7988dc0..ed0eaa2ce505c3 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx @@ -30,6 +30,7 @@ import { VerticalAlignment, XYChartSeriesIdentifier, Tooltip, + LegendValue, } from '@elastic/charts'; import { Datatable } from '@kbn/expressions-plugin/common'; import { EmptyPlaceholder } from '@kbn/charts-plugin/public'; @@ -58,7 +59,7 @@ import { XYChart, XYChartRenderProps } from './xy_chart'; import { ExtendedDataLayerConfig, XYProps, AnnotationLayerConfigResult } from '../../common/types'; import { DataLayers } from './data_layers'; import { SplitChart } from './split_chart'; -import { LegendSize, XYLegendValue } from '@kbn/visualizations-plugin/common'; +import { LegendSize } from '@kbn/visualizations-plugin/common'; import type { LayerCellValueActions } from '../types'; const onClickValue = jest.fn(); @@ -744,7 +745,7 @@ describe('XYChart component', () => { {...defaultProps} args={{ ...args, - legend: { ...args.legend, legendStats: [XYLegendValue.CurrentAndLastValue] }, + legend: { ...args.legend, legendStats: [LegendValue.CurrentAndLastValue] }, }} /> ); @@ -760,14 +761,14 @@ describe('XYChart component', () => { ...args, legend: { ...args.legend, - legendStats: [XYLegendValue.CurrentAndLastValue], + legendStats: [LegendValue.CurrentAndLastValue], }, layers: [dateHistogramLayer], }} /> ); expect(component.find(Settings).at(0).prop('legendValues')).toEqual([ - XYLegendValue.CurrentAndLastValue, + LegendValue.CurrentAndLastValue, ]); }); diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index 58a02a1bf32152..6479abbdd42d08 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -828,6 +828,8 @@ export function XYChart({ showLegend={showLegend} legendPosition={legend?.isInside ? legendInsideParams : legend.position} legendSize={LegendSizeToPixels[legend.legendSize ?? DEFAULT_LEGEND_SIZE]} + legendValues={isHistogramViz ? legend.legendStats : []} + legendTitle={getLegendTitle(legend.title, dataLayers[0], legend.isTitleVisible)} theme={[ { barSeriesStyle: { @@ -877,7 +879,6 @@ export function XYChart({ ) : undefined } - legendValues={isHistogramViz ? legend.legendStats : []} ariaLabel={args.ariaLabel} ariaUseDefaultSummary={!args.ariaLabel} orderOrdinalBinsBy={ @@ -1038,3 +1039,23 @@ export function XYChart({
); } + +const defaultLegendTitle = i18n.translate('expressionXY.xyChart.legendTitle', { + defaultMessage: 'Legend', +}); + +function getLegendTitle( + title: string | undefined, + layer?: CommonXYDataLayerConfig, + isTitleVisible?: boolean +) { + if (!isTitleVisible) { + return undefined; + } + if (typeof title === 'string' && title.length > 0) { + return title; + } + return layer?.splitAccessors?.[0] + ? getColumnByAccessor(layer.splitAccessors?.[0], layer?.table.columns)?.name + : defaultLegendTitle; +} diff --git a/src/plugins/vis_types/pie/public/convert_to_lens/configurations/index.test.ts b/src/plugins/vis_types/pie/public/convert_to_lens/configurations/index.test.ts index d1da337a87862b..5d7074ce44022d 100644 --- a/src/plugins/vis_types/pie/public/convert_to_lens/configurations/index.test.ts +++ b/src/plugins/vis_types/pie/public/convert_to_lens/configurations/index.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PartitionLegendValue } from '@kbn/visualizations-plugin/common/constants'; +import { LegendValue } from '@elastic/charts'; import { getConfiguration } from '.'; import { samplePieVis } from '../../sample_vis.test.mocks'; @@ -39,7 +39,7 @@ describe('getConfiguration', () => { percentDecimals: 2, primaryGroups: ['bucket-1'], secondaryGroups: [], - legendStats: [PartitionLegendValue.Value], + legendStats: [LegendValue.Value], truncateLegend: true, }, ], diff --git a/src/plugins/vis_types/pie/public/convert_to_lens/configurations/index.ts b/src/plugins/vis_types/pie/public/convert_to_lens/configurations/index.ts index acad50d7f3d302..dc542e9e42ff41 100644 --- a/src/plugins/vis_types/pie/public/convert_to_lens/configurations/index.ts +++ b/src/plugins/vis_types/pie/public/convert_to_lens/configurations/index.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import { LegendValue } from '@elastic/charts'; import { LegendDisplay, PartitionVisParams } from '@kbn/expression-partition-vis-plugin/common'; -import { PartitionLegendValue } from '@kbn/visualizations-plugin/common/constants'; import { CategoryDisplayTypes, NumberDisplayTypes, @@ -28,7 +28,7 @@ const getLayers = ( const showValuesInLegend = vis.params.labels.values ?? (vis.params.legendStats - ? vis.params.legendStats?.[0] === PartitionLegendValue.Value + ? vis.params.legendStats?.[0] === LegendValue.Value : vis.type.visConfig.defaults.showValuesInLegend); return [ @@ -50,7 +50,7 @@ const getLayers = ( vis.params.legendDisplay ?? vis.type.visConfig.defaults.legendDisplay, legendPosition: vis.params.legendPosition ?? vis.type.visConfig.defaults.legendPosition, - legendStats: showValuesInLegend ? [PartitionLegendValue.Value] : undefined, + legendStats: showValuesInLegend ? [LegendValue.Value] : undefined, nestedLegend: vis.params.nestedLegend ?? vis.type.visConfig.defaults.nestedLegend, percentDecimals: vis.params.labels.percentDecimals ?? vis.type.visConfig.defaults.labels.percentDecimals, diff --git a/src/plugins/vis_types/xy/public/convert_to_lens/configurations/index.ts b/src/plugins/vis_types/xy/public/convert_to_lens/configurations/index.ts index bc1bd871406548..88b60ba49a55f0 100644 --- a/src/plugins/vis_types/xy/public/convert_to_lens/configurations/index.ts +++ b/src/plugins/vis_types/xy/public/convert_to_lens/configurations/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Position, ScaleType as ECScaleType } from '@elastic/charts'; +import { LegendValue, Position, ScaleType as ECScaleType } from '@elastic/charts'; import { SeriesTypes, Column, @@ -15,7 +15,6 @@ import { XYReferenceLineLayerConfig, } from '@kbn/visualizations-plugin/common/convert_to_lens'; import { Vis } from '@kbn/visualizations-plugin/public'; -import { XYLegendValue } from '@kbn/visualizations-plugin/common/constants'; import { Layer } from '..'; import { ChartType } from '../../../common'; import { @@ -237,7 +236,7 @@ export const getConfiguration = ( maxLines: vis.params.maxLegendLines ?? vis.type.visConfig.defaults.maxLegendLines, showSingleSeries: true, legendStats: Boolean(vis.params.labels.show ?? vis.type.visConfig.defaults.labels?.show) - ? [XYLegendValue.CurrentAndLastValue] + ? [LegendValue.CurrentAndLastValue] : undefined, }, fittingFunction: fittingFunction diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index c855aae1865dd6..0a6694f1d5a8ee 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -7,7 +7,7 @@ */ import moment from 'moment'; -import { Position, ScaleType as ECScaleType } from '@elastic/charts'; +import { LegendValue, Position, ScaleType as ECScaleType } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; import { VisToExpressionAst, @@ -20,7 +20,6 @@ import { buildExpression, buildExpressionFunction } from '@kbn/expressions-plugi import { BUCKET_TYPES } from '@kbn/data-plugin/public'; import type { TimeRangeBounds } from '@kbn/data-plugin/common'; import type { PaletteOutput } from '@kbn/charts-plugin/common/expressions/palette/types'; -import { XYLegendValue } from '@kbn/visualizations-plugin/common/constants'; import { Dimensions, Dimension, @@ -48,7 +47,7 @@ const prepareLengend = (params: VisParams, legendSize?: LegendSize) => { shouldTruncate: params.truncateLegend, showSingleSeries: true, legendSize, - legendStats: params.labels.show ? [XYLegendValue.CurrentAndLastValue] : undefined, + legendStats: params.labels.show ? [LegendValue.CurrentAndLastValue] : undefined, }); return buildExpression([legend]); diff --git a/src/plugins/visualizations/common/constants.ts b/src/plugins/visualizations/common/constants.ts index f8f6409b711226..4ae3e174fc5c60 100644 --- a/src/plugins/visualizations/common/constants.ts +++ b/src/plugins/visualizations/common/constants.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { LegendValue } from '@elastic/charts'; import { METRIC_TYPES, BUCKET_TYPES } from '@kbn/data-plugin/common'; export const SAVED_OBJECTS_LIMIT_SETTING = 'savedObjects:listingLimit'; @@ -37,6 +38,11 @@ export enum LegendSize { EXTRA_LARGE = 'xlarge', } +export enum LegendLayout { + Table = 'table', + List = 'list', +} + export const LegendSizeToPixels = { [LegendSize.AUTO]: undefined, [LegendSize.SMALL]: 80, @@ -52,10 +58,25 @@ export const SUPPORTED_AGGREGATIONS = [ ...Object.values(BUCKET_TYPES), ] as const; -export enum XYLegendValue { - CurrentAndLastValue = 'currentAndLastValue', -} +export type XYLegendValue = Extract< + LegendValue, + | 'currentAndLastValue' + | 'lastValue' + | 'lastNonNullValue' + | 'average' + | 'median' + | 'max' + | 'min' + | 'firstValue' + | 'firstNonNullValue' + | 'total' + | 'count' + | 'distinctCount' + | 'variance' + | 'stdDeviation' + | 'range' + | 'difference' + | 'differencePercent' +>; -export enum PartitionLegendValue { - Value = 'value', -} +export type PartitionLegendValue = Extract; diff --git a/src/plugins/visualizations/common/convert_to_lens/types/configurations.ts b/src/plugins/visualizations/common/convert_to_lens/types/configurations.ts index 675355dc693151..d167935720cf47 100644 --- a/src/plugins/visualizations/common/convert_to_lens/types/configurations.ts +++ b/src/plugins/visualizations/common/convert_to_lens/types/configurations.ts @@ -10,7 +10,7 @@ import { HorizontalAlignment, LayoutDirection, Position, VerticalAlignment } fro import { $Values } from '@kbn/utility-types'; import type { CustomPaletteParams, PaletteOutput } from '@kbn/coloring'; import { KibanaQueryOutput } from '@kbn/data-plugin/common'; -import { LegendSize, XYLegendValue, PartitionLegendValue } from '../../constants'; +import { LegendSize, type XYLegendValue, type PartitionLegendValue } from '../../constants'; import { CategoryDisplayTypes, PartitionChartTypes, diff --git a/src/plugins/visualizations/common/index.ts b/src/plugins/visualizations/common/index.ts index f5047212603c19..82dfd8d76b29a2 100644 --- a/src/plugins/visualizations/common/index.ts +++ b/src/plugins/visualizations/common/index.ts @@ -20,6 +20,7 @@ export { LegendSize, LegendSizeToPixels, DEFAULT_LEGEND_SIZE, - XYLegendValue, - PartitionLegendValue, + LegendLayout, + type XYLegendValue, + type PartitionLegendValue, } from './constants'; diff --git a/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.tsx b/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.tsx deleted file mode 100644 index a65425d07d7a08..00000000000000 --- a/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.tsx +++ /dev/null @@ -1,101 +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, { useCallback, useMemo } from 'react'; -import { EuiSpacer, EuiFormRow } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { useDebouncedValue } from '@kbn/visualization-ui-components'; -import type { AxesSettingsConfig } from '../../../visualizations/xy/types'; -import { type LabelMode, VisLabel } from '../..'; - -type AxesSettingsConfigKeys = keyof AxesSettingsConfig; - -export interface AxisTitleSettingsProps { - /** - * Determines the axis - */ - axis: AxesSettingsConfigKeys; - /** - * Determines the axis title - */ - axisTitle: string | undefined; - /** - * Callback to axis title change for both title and visibility - */ - updateTitleState: ( - state: { title?: string; visible: boolean }, - axis: AxesSettingsConfigKeys - ) => void; - /** - * Determines if the title visibility switch is on and the input text is disabled - */ - isAxisTitleVisible: boolean; -} - -export const AxisTitleSettings: React.FunctionComponent = ({ - axis, - axisTitle, - updateTitleState, - isAxisTitleVisible, -}) => { - const axisState = useMemo( - () => ({ - title: axisTitle, - visibility: - !axisTitle && isAxisTitleVisible - ? 'auto' - : isAxisTitleVisible - ? 'custom' - : ('none' as LabelMode), - }), - [axisTitle, isAxisTitleVisible] - ); - const onTitleChange = useCallback( - ({ title, visibility }: { title?: string; visibility: LabelMode }) => - updateTitleState({ title, visible: visibility !== 'none' }, axis), - [axis, updateTitleState] - ); - const { inputValue: localAxisState, handleInputChange: onLocalTitleChange } = useDebouncedValue<{ - title?: string; - visibility: LabelMode; - }>( - { - value: axisState, - onChange: onTitleChange, - }, - { allowFalsyValue: true } - ); - - return ( - <> - - { - onLocalTitleChange({ title: label, visibility: mode }); - }} - /> - - - - ); -}; diff --git a/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.test.tsx b/x-pack/plugins/lens/public/shared_components/axis/title/toolbar_title_settings.test.tsx similarity index 80% rename from x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.test.tsx rename to x-pack/plugins/lens/public/shared_components/axis/title/toolbar_title_settings.test.tsx index 7783ce163830ad..807e02ff056415 100644 --- a/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.test.tsx +++ b/x-pack/plugins/lens/public/shared_components/axis/title/toolbar_title_settings.test.tsx @@ -6,16 +6,16 @@ */ import React from 'react'; -import { AxisTitleSettings, AxisTitleSettingsProps } from './axis_title_settings'; +import { ToolbarTitleSettings, TitleSettingsProps } from './toolbar_title_settings'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -const renderAxisTicksSettings = (propsOverrides?: Partial) => { +const renderAxisTicksSettings = (propsOverrides?: Partial) => { const rtlRender = render( - @@ -35,33 +35,33 @@ describe('Axes Title settings', () => { }); it('should set the mode to Auto if no title is passed over', () => { - const { getAxisTitleInput } = renderAxisTicksSettings({ axisTitle: undefined }); + const { getAxisTitleInput } = renderAxisTicksSettings({ title: undefined }); expect(getAxisTitleInput()).toHaveValue(''); }); it('should set the mode to Auto if empty title is passed over', () => { - const { getAxisTitleInput } = renderAxisTicksSettings({ axisTitle: '' }); + const { getAxisTitleInput } = renderAxisTicksSettings({ title: '' }); expect(getAxisTitleInput()).toHaveValue(''); }); it('should set the mode to None if empty title is passed over and the visibility is set to false', () => { const { getAxisTitleSelect } = renderAxisTicksSettings({ - axisTitle: '', - isAxisTitleVisible: false, + title: '', + isTitleVisible: false, }); expect(getAxisTitleSelect()).toHaveValue('none'); }); it('should disable the input text if the switch is off', () => { const { getAxisTitleInput } = renderAxisTicksSettings({ - isAxisTitleVisible: false, + isTitleVisible: false, }); expect(getAxisTitleInput()).toBeDisabled(); }); it('should allow custom mode on user input even with empty string', () => { const { getAxisTitleSelect, getAxisTitleInput } = renderAxisTicksSettings({ - axisTitle: '', + title: '', }); userEvent.selectOptions(getAxisTitleSelect(), 'custom'); expect(getAxisTitleSelect()).toHaveValue('custom'); @@ -71,8 +71,8 @@ describe('Axes Title settings', () => { it('should reset the label when moving from custom to auto', async () => { const updateTitleStateSpy = jest.fn(); const { getAxisTitleSelect, getAxisTitleInput } = renderAxisTicksSettings({ - isAxisTitleVisible: true, - axisTitle: 'Custom title', + isTitleVisible: true, + title: 'Custom title', updateTitleState: updateTitleStateSpy, }); userEvent.selectOptions(getAxisTitleSelect(), 'auto'); diff --git a/x-pack/plugins/lens/public/shared_components/axis/title/toolbar_title_settings.tsx b/x-pack/plugins/lens/public/shared_components/axis/title/toolbar_title_settings.tsx new file mode 100644 index 00000000000000..258e41624402d9 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/axis/title/toolbar_title_settings.tsx @@ -0,0 +1,107 @@ +/* + * 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, useMemo } from 'react'; +import { EuiSpacer, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useDebouncedValue } from '@kbn/visualization-ui-components'; +import type { AxesSettingsConfig } from '../../../visualizations/xy/types'; +import { type LabelMode, VisLabel } from '../..'; + +type SettingsConfigKeys = keyof AxesSettingsConfig | 'legend'; + +export interface TitleSettingsProps { + /** + * Determines the settingId - either axis or legend + */ + settingId: SettingsConfigKeys; + /** + * Determines the title + */ + title: string | undefined; + /** + * Callback to title change for both title and visibility + */ + updateTitleState: ( + state: { title?: string; visible: boolean }, + settingId: SettingsConfigKeys + ) => void; + /** + * Determines if the title visibility switch is on and the input text is disabled + */ + isTitleVisible: boolean; + strings?: { + header: string; + label: string; + getDataTestSubj: (axis: SettingsConfigKeys) => string; + }; + placeholder?: string; +} + +const axisStrings = { + header: i18n.translate('xpack.lens.label.shared.axisHeader', { + defaultMessage: 'Axis title', + }), + label: i18n.translate('xpack.lens.shared.axisNameLabel', { + defaultMessage: 'Axis title', + }), + getDataTestSubj: (axis: SettingsConfigKeys) => `lns${axis}AxisTitle`, +}; + +export const ToolbarTitleSettings: React.FunctionComponent = ({ + settingId, + title, + updateTitleState, + isTitleVisible, + strings = axisStrings, + placeholder = i18n.translate('xpack.lens.shared.overwriteAxisTitle', { + defaultMessage: 'Overwrite axis title', + }), +}) => { + const axisState = useMemo( + () => ({ + title, + visibility: + !title && isTitleVisible ? 'auto' : isTitleVisible ? 'custom' : ('none' as LabelMode), + }), + [title, isTitleVisible] + ); + const onTitleChange = useCallback( + ({ title: t, visibility }: { title?: string; visibility: LabelMode }) => + updateTitleState({ title: t, visible: visibility !== 'none' }, settingId), + [settingId, updateTitleState] + ); + const { inputValue: localState, handleInputChange: onLocalTitleChange } = useDebouncedValue<{ + title?: string; + visibility: LabelMode; + }>( + { + value: axisState, + onChange: onTitleChange, + }, + { allowFalsyValue: true } + ); + + return ( + <> + + { + onLocalTitleChange({ title: label, visibility: mode }); + }} + /> + + + + ); +}; diff --git a/x-pack/plugins/lens/public/shared_components/index.ts b/x-pack/plugins/lens/public/shared_components/index.ts index cd663ca08601e4..1e3f84dd2accbe 100644 --- a/x-pack/plugins/lens/public/shared_components/index.ts +++ b/x-pack/plugins/lens/public/shared_components/index.ts @@ -22,7 +22,7 @@ export { export * from './coloring'; export * from './helpers'; export { ValueLabelsSettings } from './value_labels_settings'; -export { AxisTitleSettings } from './axis/title/axis_title_settings'; +export { ToolbarTitleSettings } from './axis/title/toolbar_title_settings'; export { AxisTicksSettings } from './axis/ticks/axis_ticks_settings'; export * from './static_header'; export * from './vis_label'; diff --git a/x-pack/plugins/lens/public/shared_components/legend/layout/columns_number_setting.tsx b/x-pack/plugins/lens/public/shared_components/legend/layout/columns_number_setting.tsx index 1f21c9004043e8..81d1acd84e0fe3 100644 --- a/x-pack/plugins/lens/public/shared_components/legend/layout/columns_number_setting.tsx +++ b/x-pack/plugins/lens/public/shared_components/legend/layout/columns_number_setting.tsx @@ -22,22 +22,22 @@ interface ColumnsNumberSettingProps { */ onFloatingColumnsChange?: (value: number) => void; /** - * Indicates if legend is located outside + * Indicates if the component should be hidden */ - isLegendOutside: boolean; + isHidden: boolean; } export const ColumnsNumberSetting = ({ floatingColumns, onFloatingColumnsChange = () => {}, - isLegendOutside, + isHidden, }: ColumnsNumberSettingProps) => { const { inputValue, handleInputChange } = useDebouncedValue({ value: floatingColumns ?? DEFAULT_FLOATING_COLUMNS, onChange: onFloatingColumnsChange, }); - if (isLegendOutside) return null; + if (isHidden) return null; return ( { let defaultProps: LegendSettingsPopoverProps; @@ -49,7 +50,6 @@ describe('Legend Settings', () => { renderOptions ); const openLegendPopover = () => userEvent.click(screen.getByRole('button', { name: 'Legend' })); - openLegendPopover(); return { @@ -125,4 +125,28 @@ describe('Legend Settings', () => { renderLegendSettingsPopover({ mode: 'hide', renderNestedLegendSwitch: true }); expect(screen.queryByRole('switch', { name: 'Nested' })).toBeNull(); }); + + it('should display allowed legend stats', () => { + const onLegendStatsChange = jest.fn(); + renderLegendSettingsPopover({ + allowedLegendStats: [ + { + label: 'Current and last value', + value: LegendValue.CurrentAndLastValue, + toolTipContent: 'Shows the current and last value', + }, + { + label: 'Average', + value: LegendValue.Average, + toolTipContent: 'Shows the average value', + }, + ], + onLegendStatsChange, + }); + expect(screen.queryByRole('button', { name: 'Layout' })).toBeNull(); + fireEvent.click(screen.getByRole('combobox', { name: 'Statistics' })); + fireEvent.click(screen.getByRole('option', { name: 'Current and last value' })); + // expect(screen.getByRole('group', { name: 'Layout' })).toBeInTheDocument(); + expect(onLegendStatsChange).toBeCalledWith([LegendValue.CurrentAndLastValue], false); + }); }); diff --git a/x-pack/plugins/lens/public/shared_components/legend/legend_settings_popover.tsx b/x-pack/plugins/lens/public/shared_components/legend/legend_settings_popover.tsx index ccfdaa29089b17..80389e041763ff 100644 --- a/x-pack/plugins/lens/public/shared_components/legend/legend_settings_popover.tsx +++ b/x-pack/plugins/lens/public/shared_components/legend/legend_settings_popover.tsx @@ -15,8 +15,10 @@ import { EuiFieldNumber, EuiFlexItem, EuiFlexGroup, + EuiComboBox, + EuiHorizontalRule, } from '@elastic/eui'; -import { Position, VerticalAlignment, HorizontalAlignment } from '@elastic/charts'; +import { Position, VerticalAlignment, HorizontalAlignment, LegendValue } from '@elastic/charts'; import { LegendSize } from '@kbn/visualizations-plugin/public'; import { useDebouncedValue } from '@kbn/visualization-ui-components'; import { XYLegendValue } from '@kbn/visualizations-plugin/common/constants'; @@ -24,8 +26,10 @@ import { ToolbarPopover, type ToolbarPopoverProps } from '../toolbar_popover'; import { LegendLocationSettings } from './location/legend_location_settings'; import { ColumnsNumberSetting } from './layout/columns_number_setting'; import { LegendSizeSettings } from './size/legend_size_settings'; +import { nonNullable } from '../../utils'; +import { ToolbarTitleSettings } from '../axis/title/toolbar_title_settings'; -export interface LegendSettingsPopoverProps { +export interface LegendSettingsPopoverProps { /** * Determines the legend display options */ @@ -107,17 +111,18 @@ export interface LegendSettingsPopoverProps { */ onNestedLegendChange?: (event: EuiSwitchEvent) => void; /** - * value in legend status + * current value in legend stats */ - legendStats?: S[]; + legendStats?: LegendStats[]; /** - * Callback on value in legend status change + * legend statistics that are allowed */ - onLegendStatsChange?: (checked?: boolean) => void; + allowedLegendStats?: Array<{ label: string; value: LegendStats; toolTipContent?: string }>; /** - * If true, value in legend switch is rendered + * Callback on value in legend stats change */ - allowLegendStats?: boolean; + onLegendStatsChange?: (legendStats?: LegendStats[], hasConvertedToTable?: boolean) => void; + /** * Button group position */ @@ -135,6 +140,10 @@ export interface LegendSettingsPopoverProps { * (We're trying to get people to stop using it so it can eventually be removed.) */ showAutoLegendSizeOption: boolean; + titlePlaceholder?: string; + legendTitle?: string; + isTitleVisible?: boolean; + onLegendTitleChange?: (state: { title?: string; visible: boolean }) => void; } const DEFAULT_TRUNCATE_LINES = 1; @@ -182,9 +191,30 @@ const PANEL_STYLE = { width: '500px', }; -export function LegendSettingsPopover({ +const legendTitleStrings = { + header: i18n.translate('xpack.lens.label.shared.legendHeader', { + defaultMessage: 'Series header', + }), + label: i18n.translate('xpack.lens.shared.Lagend ', { + defaultMessage: 'Series header', + }), + placeholder: i18n.translate('xpack.lens.shared.overwriteLegendTitle', { + defaultMessage: 'Overwrite series header', + }), + getDataTestSubj: () => `lnsLegendTableSeriesHeader`, +}; + +export function shouldDisplayTable(legendValues: LegendValue[]) { + return legendValues.some((v) => v !== LegendValue.CurrentAndLastValue); +} + +export function LegendSettingsPopover({ + allowedLegendStats = [], legendOptions, mode, + legendTitle, + isTitleVisible, + onLegendTitleChange, onDisplayChange, position, location, @@ -198,9 +228,8 @@ export function LegendSettingsPopover({ renderNestedLegendSwitch, nestedLegend, onNestedLegendChange = noop, - legendStats, + legendStats = [], onLegendStatsChange = noop, - allowLegendStats, groupPosition = 'right', maxLines, onMaxLinesChange = noop, @@ -209,7 +238,20 @@ export function LegendSettingsPopover({ legendSize, onLegendSizeChange, showAutoLegendSizeOption, -}: LegendSettingsPopoverProps) { + titlePlaceholder, +}: LegendSettingsPopoverProps) { + const isLegendNotHidden = mode !== 'hide'; + + const showsStatisticsSetting = isLegendNotHidden && allowedLegendStats.length > 1; + + const showsShowValueSetting = + isLegendNotHidden && + allowedLegendStats.length === 1 && + (allowedLegendStats[0].value === LegendValue.CurrentAndLastValue || + allowedLegendStats[0].value === LegendValue.Value); + + const showsLegendTitleSetting = shouldDisplayTable(legendStats) && !!onLegendTitleChange; + return ( ({ ({ onChange={onDisplayChange} /> - {mode !== 'hide' && ( + + {isLegendNotHidden && ( <> ({ )} + + )} + {showsStatisticsSetting && ( + <> + - - - - - - - - + allowedLegendStats.find((option) => option.value === value)) + .filter(nonNullable)} + onChange={(options) => { + const newLegendStats = options.map(({ value }) => value).filter(nonNullable); + const hasConvertedToTable = + !shouldDisplayTable(legendStats) && shouldDisplayTable(newLegendStats); + onLegendStatsChange(newLegendStats, hasConvertedToTable); + }} + isClearable={true} + compressed + /> + + )} - {renderNestedLegendSwitch && ( - + {showsLegendTitleSetting && ( + + )} + {showsShowValueSetting && ( + + { + onLegendStatsChange(ev.target.checked ? [allowedLegendStats[0].value] : []); + }} + /> + + )} + + {isLegendNotHidden && ( + + + - - )} - {allowLegendStats && ( - - { - onLegendStatsChange(ev.target.checked); - }} + + + - - )} - + +
+ + )} + + {isLegendNotHidden && renderNestedLegendSwitch && ( + + + )} ); diff --git a/x-pack/plugins/lens/public/shared_components/legend/location/legend_location_settings.tsx b/x-pack/plugins/lens/public/shared_components/legend/location/legend_location_settings.tsx index 039f778d7439ee..5c28b2e2a0888f 100644 --- a/x-pack/plugins/lens/public/shared_components/legend/location/legend_location_settings.tsx +++ b/x-pack/plugins/lens/public/shared_components/legend/location/legend_location_settings.tsx @@ -158,7 +158,7 @@ export const LegendLocationSettings: React.FunctionComponent @@ -167,7 +167,7 @@ export const LegendLocationSettings: React.FunctionComponent diff --git a/x-pack/plugins/lens/public/shared_components/vis_label.tsx b/x-pack/plugins/lens/public/shared_components/vis_label.tsx index 6d54d1633d4395..10c8f3ea42ed6c 100644 --- a/x-pack/plugins/lens/public/shared_components/vis_label.tsx +++ b/x-pack/plugins/lens/public/shared_components/vis_label.tsx @@ -76,10 +76,9 @@ export function VisLabel({ data-test-subj={`${dataTestSubj}-select`} aria-label="Label" onChange={({ target }) => { - const title = - target.value === 'custom' ? '' : target.value === 'auto' ? undefined : label; handleChange({ - label: title, + // reset title to undefined when switching mode + label: undefined, mode: target.value as LabelMode, }); }} diff --git a/x-pack/plugins/lens/public/visualizations/heatmap/toolbar_component.tsx b/x-pack/plugins/lens/public/visualizations/heatmap/toolbar_component.tsx index c621a59e9ea9b5..327bdef6c5bc48 100644 --- a/x-pack/plugins/lens/public/visualizations/heatmap/toolbar_component.tsx +++ b/x-pack/plugins/lens/public/visualizations/heatmap/toolbar_component.tsx @@ -17,7 +17,7 @@ import { LegendSettingsPopover, ToolbarPopover, ValueLabelsSettings, - AxisTitleSettings, + ToolbarTitleSettings, AxisTicksSettings, } from '../../shared_components'; import type { HeatmapVisualizationState } from './types'; @@ -151,9 +151,9 @@ export const HeatmapToolbar = memo( buttonDataTestSubj="lnsHeatmapVerticalAxisButton" panelClassName="lnsVisToolbarAxis__popover" > - { setState({ ...state, @@ -164,7 +164,7 @@ export const HeatmapToolbar = memo( }, }); }} - isAxisTitleVisible={state?.gridConfig.isYAxisTitleVisible} + isTitleVisible={state?.gridConfig.isYAxisTitleVisible} /> - setState({ ...state, @@ -210,7 +210,7 @@ export const HeatmapToolbar = memo( }, }) } - isAxisTitleVisible={state?.gridConfig.isXAxisTitleVisible} + isTitleVisible={state?.gridConfig.isXAxisTitleVisible} /> = { }, legend: { flat: true, - defaultLegendStats: [PartitionLegendValue.Value], + defaultLegendStats: [LegendValue.Value], hideNestedLegendSwitch: true, getShowLegendDefault: () => true, }, diff --git a/x-pack/plugins/lens/public/visualizations/partition/persistence.tsx b/x-pack/plugins/lens/public/visualizations/partition/persistence.tsx index 9fc04b3702296d..ba8632659836ac 100644 --- a/x-pack/plugins/lens/public/visualizations/partition/persistence.tsx +++ b/x-pack/plugins/lens/public/visualizations/partition/persistence.tsx @@ -5,8 +5,8 @@ * 2.0. */ +import { LegendValue } from '@elastic/charts'; import { cloneDeep } from 'lodash'; -import { PartitionLegendValue } from '@kbn/visualizations-plugin/common/constants'; import { PieLayerState, PieVisualizationState } from '../../../common/types'; type PersistedPieLayerState = PieLayerState & { @@ -28,7 +28,7 @@ function convertToLegendStats(state: PieVisualizationState) { if ('showValuesInLegend' in l) { l.legendStats = [ ...new Set([ - ...(l.showValuesInLegend ? [PartitionLegendValue.Value] : []), + ...(l.showValuesInLegend ? [LegendValue.Value] : []), ...(l.legendStats || []), ]), ]; diff --git a/x-pack/plugins/lens/public/visualizations/partition/render_helpers.test.ts b/x-pack/plugins/lens/public/visualizations/partition/render_helpers.test.ts index e273fde23f4db5..bef4db9d0a2f6e 100644 --- a/x-pack/plugins/lens/public/visualizations/partition/render_helpers.test.ts +++ b/x-pack/plugins/lens/public/visualizations/partition/render_helpers.test.ts @@ -10,7 +10,7 @@ import type { Datatable } from '@kbn/expressions-plugin/public'; import { checkTableForContainsSmallValues, getLegendStats } from './render_helpers'; import { PieLayerState } from '../../../common/types'; import { PieChartTypes } from '../../../common/constants'; -import { PartitionLegendValue } from '@kbn/visualizations-plugin/common/constants'; +import { LegendValue } from '@elastic/charts'; describe('render helpers', () => { describe('#checkTableForContainsSmallValues', () => { @@ -72,28 +72,22 @@ describe('render helpers', () => { describe('#getLegendStats', () => { it('should firstly read the state value', () => { expect( - getLegendStats( - { legendStats: [PartitionLegendValue.Value] } as PieLayerState, - PieChartTypes.WAFFLE - ) - ).toEqual([PartitionLegendValue.Value]); + getLegendStats({ legendStats: [LegendValue.Value] } as PieLayerState, PieChartTypes.WAFFLE) + ).toEqual([LegendValue.Value]); expect( - getLegendStats( - { legendStats: [] as PartitionLegendValue[] } as PieLayerState, - PieChartTypes.WAFFLE - ) + getLegendStats({ legendStats: [] as LegendValue[] } as PieLayerState, PieChartTypes.WAFFLE) ).toEqual([]); }); it('should read value from meta in case of value in state is undefined', () => { expect(getLegendStats({} as PieLayerState, PieChartTypes.WAFFLE)).toEqual([ - PartitionLegendValue.Value, + LegendValue.Value, ]); expect( getLegendStats({ legendStats: undefined } as PieLayerState, PieChartTypes.WAFFLE) - ).toEqual([PartitionLegendValue.Value]); + ).toEqual([LegendValue.Value]); expect(getLegendStats({} as PieLayerState, PieChartTypes.PIE)).toEqual(undefined); }); diff --git a/x-pack/plugins/lens/public/visualizations/partition/render_helpers.ts b/x-pack/plugins/lens/public/visualizations/partition/render_helpers.ts index 869597f92dcb12..b2bd2cdd9a058b 100644 --- a/x-pack/plugins/lens/public/visualizations/partition/render_helpers.ts +++ b/x-pack/plugins/lens/public/visualizations/partition/render_helpers.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { LegendValue } from '@elastic/charts'; import type { Datatable } from '@kbn/expressions-plugin/public'; -import { PartitionLegendValue } from '@kbn/visualizations-plugin/common/constants'; import type { PieChartType, PieLayerState } from '../../../common/types'; import { PartitionChartsMeta } from './partition_charts_meta'; @@ -14,7 +14,7 @@ export const getLegendStats = (layer: PieLayerState, shape: PieChartType) => { if ('defaultLegendStats' in PartitionChartsMeta[shape]?.legend) { return ( layer.legendStats ?? - PartitionChartsMeta[shape].legend.defaultLegendStats ?? [PartitionLegendValue.Value] + PartitionChartsMeta[shape].legend.defaultLegendStats ?? [LegendValue.Value] ); } }; diff --git a/x-pack/plugins/lens/public/visualizations/partition/toolbar.tsx b/x-pack/plugins/lens/public/visualizations/partition/toolbar.tsx index 792e45ba99b2bc..dfccdccc9f85f5 100644 --- a/x-pack/plugins/lens/public/visualizations/partition/toolbar.tsx +++ b/x-pack/plugins/lens/public/visualizations/partition/toolbar.tsx @@ -16,10 +16,10 @@ import { EuiHorizontalRule, EuiButtonGroup, } from '@elastic/eui'; -import type { Position } from '@elastic/charts'; +import { LegendValue, Position } from '@elastic/charts'; import { LegendSize } from '@kbn/visualizations-plugin/public'; import { useDebouncedValue } from '@kbn/visualization-ui-components'; -import { PartitionLegendValue } from '@kbn/visualizations-plugin/common/constants'; +import { type PartitionLegendValue } from '@kbn/visualizations-plugin/common/constants'; import { DEFAULT_PERCENT_DECIMALS } from './constants'; import { PartitionChartsMeta } from './partition_charts_meta'; import { PieVisualizationState, SharedPieLayerState } from '../../../common/types'; @@ -29,6 +29,15 @@ import { ToolbarPopover, LegendSettingsPopover } from '../../shared_components'; import { getDefaultVisualValuesForLayer } from '../../shared_components/datasource_default_values'; import { getLegendStats } from './render_helpers'; +const partitionLegendValues = [ + { + value: LegendValue.Value, + label: i18n.translate('xpack.lens.shared.legendValues.value', { + defaultMessage: 'Value', + }), + }, +]; + const legendOptions: Array<{ value: SharedPieLayerState['legendDisplay']; label: string; @@ -135,10 +144,8 @@ export function PieToolbar(props: VisualizationToolbarProps { - onStateChange({ - legendStats: checked ? [PartitionLegendValue.Value] : [], - }); + (legendStats) => { + onStateChange({ legendStats }); }, [onStateChange] ); @@ -250,7 +257,11 @@ export function PieToolbar(props: VisualizationToolbarProps { describe('converting to legendStats', () => { it('loads a chart with `legendStats` property', () => { const persistedState = getExampleState(); - persistedState.layers[0].legendStats = [PartitionLegendValue.Value]; + persistedState.layers[0].legendStats = [LegendValue.Value]; const runtimeState = pieVisualization.initialize(() => 'first', persistedState); diff --git a/x-pack/plugins/lens/public/visualizations/xy/legend_stats_telemetry_helpers.test.ts b/x-pack/plugins/lens/public/visualizations/xy/legend_stats_telemetry_helpers.test.ts new file mode 100644 index 00000000000000..16bc56cf983a9c --- /dev/null +++ b/x-pack/plugins/lens/public/visualizations/xy/legend_stats_telemetry_helpers.test.ts @@ -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 { LegendValue } from '@elastic/charts'; +import { getLegendStatsTelemetryEvents } from './legend_stats_telemetry_helpers'; + +describe('legend_stats_telemetry_helpers', () => { + it('no events if legend stats are not defined', () => { + expect(getLegendStatsTelemetryEvents(undefined)).toEqual([]); + }); + it('ignores single CurrentAndLastValue stat as it does not trigger table view', () => { + expect(getLegendStatsTelemetryEvents([LegendValue.CurrentAndLastValue])).toEqual([]); + expect( + getLegendStatsTelemetryEvents([LegendValue.CurrentAndLastValue, LegendValue.Average]) + ).toEqual([ + 'lens_legend_stats', + 'lens_legend_stats_currentAndLastValue', + 'lens_legend_stats_average', + 'lens_legend_stats_amount_2', + ]); + }); + + it('no events if no changes made in color mapping', () => { + expect(getLegendStatsTelemetryEvents([LegendValue.Average], [LegendValue.Average])).toEqual([]); + expect( + getLegendStatsTelemetryEvents( + [LegendValue.CurrentAndLastValue, LegendValue.Average], + [LegendValue.CurrentAndLastValue, LegendValue.Average] + ) + ).toEqual([]); + }); + describe('calculates counter events properly', () => { + it('returns single count event', () => { + expect(getLegendStatsTelemetryEvents([LegendValue.Average])).toEqual([ + 'lens_legend_stats', + 'lens_legend_stats_average', + 'lens_legend_stats_amount_1', + ]); + }); + it('returns 2 count event', () => { + expect(getLegendStatsTelemetryEvents([LegendValue.Average, LegendValue.Count])).toEqual([ + 'lens_legend_stats', + 'lens_legend_stats_average', + 'lens_legend_stats_count', + 'lens_legend_stats_amount_2', + ]); + }); + it('returns 3 count event', () => { + expect( + getLegendStatsTelemetryEvents([ + LegendValue.Average, + LegendValue.Count, + LegendValue.CurrentAndLastValue, + ]) + ).toEqual([ + 'lens_legend_stats', + 'lens_legend_stats_average', + 'lens_legend_stats_count', + 'lens_legend_stats_currentAndLastValue', + 'lens_legend_stats_amount_3', + ]); + }); + it('returns 4 count event', () => { + expect( + getLegendStatsTelemetryEvents([ + LegendValue.CurrentAndLastValue, + LegendValue.Max, + LegendValue.Min, + LegendValue.Average, + ]) + ).toEqual([ + 'lens_legend_stats', + 'lens_legend_stats_currentAndLastValue', + 'lens_legend_stats_max', + 'lens_legend_stats_min', + 'lens_legend_stats_average', + 'lens_legend_stats_amount_4_to_7', + ]); + }); + + it('returns >8 count event', () => { + expect( + getLegendStatsTelemetryEvents([ + LegendValue.CurrentAndLastValue, + LegendValue.Max, + LegendValue.Min, + LegendValue.Average, + LegendValue.Count, + LegendValue.Total, + LegendValue.LastValue, + LegendValue.FirstValue, + LegendValue.Median, + ]) + ).toEqual([ + 'lens_legend_stats', + 'lens_legend_stats_currentAndLastValue', + 'lens_legend_stats_max', + 'lens_legend_stats_min', + 'lens_legend_stats_average', + 'lens_legend_stats_count', + 'lens_legend_stats_total', + 'lens_legend_stats_lastValue', + 'lens_legend_stats_firstValue', + 'lens_legend_stats_median', + 'lens_legend_stats_amount_above_8', + ]); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/visualizations/xy/legend_stats_telemetry_helpers.ts b/x-pack/plugins/lens/public/visualizations/xy/legend_stats_telemetry_helpers.ts new file mode 100644 index 00000000000000..87143688c206d3 --- /dev/null +++ b/x-pack/plugins/lens/public/visualizations/xy/legend_stats_telemetry_helpers.ts @@ -0,0 +1,49 @@ +/* + * 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 { isEqual } from 'lodash'; +import { XYLegendValue } from '@kbn/visualizations-plugin/common'; +import { nonNullable } from '../../utils'; +import { shouldDisplayTable } from '../../shared_components/legend/legend_settings_popover'; + +const LEGEND_STATS_PREFIX = 'lens_legend_stats'; +const constructName = (eventName: string) => `${LEGEND_STATS_PREFIX}${eventName}`; + +export const getLegendStatsTelemetryEvents = ( + legendStats: XYLegendValue[] | undefined, + prevLegendStats?: XYLegendValue[] | undefined +) => { + if (!legendStats || !legendStats.length || isEqual(legendStats, prevLegendStats)) { + return []; + } + if (!shouldDisplayTable(legendStats)) { + return []; + } + const mainEvent = LEGEND_STATS_PREFIX; + const typesEvents = legendStats.map((legendStat) => { + return constructName(`_${legendStat}`); + }); + const counterText = getRangeText(legendStats.length); + const counterEvent = counterText ? constructName(counterText) : undefined; + + return [mainEvent, ...typesEvents, counterEvent].filter(nonNullable); +}; + +function getRangeText(n: number) { + if (n < 1) { + return; + } + if (n < 4) { + return `_amount_${String(n)}`; + } + if (n >= 4 && n <= 7) { + return '_amount_4_to_7'; + } + if (n >= 8) { + return '_amount_above_8'; + } +} diff --git a/x-pack/plugins/lens/public/visualizations/xy/persistence.ts b/x-pack/plugins/lens/public/visualizations/xy/persistence.ts index 5191cc96bac3d4..8ad5d82d364e22 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/persistence.ts +++ b/x-pack/plugins/lens/public/visualizations/xy/persistence.ts @@ -9,8 +9,8 @@ import { v4 as uuidv4 } from 'uuid'; import type { SavedObjectReference } from '@kbn/core/public'; import { EVENT_ANNOTATION_GROUP_TYPE } from '@kbn/event-annotation-common'; import { cloneDeep } from 'lodash'; -import { XYLegendValue } from '@kbn/visualizations-plugin/common/constants'; +import { LegendValue } from '@elastic/charts'; import { layerTypes } from '../../../common/layer_types'; import { AnnotationGroups } from '../../types'; import { @@ -278,7 +278,7 @@ function convertToLegendStats(state: XYState & { valuesInLegend?: unknown }) { ...state.legend, legendStats: [ ...new Set([ - ...(valuesInLegend ? [XYLegendValue.CurrentAndLastValue] : []), + ...(valuesInLegend ? [LegendValue.CurrentAndLastValue] : []), ...(state.legend.legendStats || []), ]), ], diff --git a/x-pack/plugins/lens/public/visualizations/xy/to_expression.ts b/x-pack/plugins/lens/public/visualizations/xy/to_expression.ts index 76e00c892d2436..c756c4eb137a9f 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/to_expression.ts +++ b/x-pack/plugins/lens/public/visualizations/xy/to_expression.ts @@ -293,6 +293,7 @@ export const buildXYExpression = ( : state.legend.legendSize ? state.legend.legendSize : undefined, + layout: state.legend.layout, horizontalAlignment: state.legend.horizontalAlignment && state.legend.isInside ? state.legend.horizontalAlignment @@ -309,6 +310,8 @@ export const buildXYExpression = ( : [], maxLines: state.legend.maxLines, legendStats: state.legend.legendStats, + title: state.legend.title, + isTitleVisible: state.legend.isTitleVisible, shouldTruncate: state.legend.shouldTruncate ?? getDefaultVisualValuesForLayer(state, datasourceLayers).truncateText, diff --git a/x-pack/plugins/lens/public/visualizations/xy/visualization.test.tsx b/x-pack/plugins/lens/public/visualizations/xy/visualization.test.tsx index 73802ac2b4c472..03a391d4e29d61 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/visualization.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/visualization.test.tsx @@ -6,7 +6,7 @@ */ import { type ExtraAppendLayerArg, getXyVisualization } from './visualization'; -import { Position } from '@elastic/charts'; +import { LegendValue, Position } from '@elastic/charts'; import { Operation, OperationDescriptor, @@ -53,7 +53,6 @@ import { } from './visualization_helpers'; import { cloneDeep } from 'lodash'; import { DataViewsServicePublic } from '@kbn/data-views-plugin/public'; -import { XYLegendValue } from '@kbn/visualizations-plugin/common/constants'; import { XYPersistedByReferenceAnnotationLayerConfig, XYPersistedByValueAnnotationLayerConfig, @@ -612,7 +611,7 @@ describe('xy_visualization', () => { ...exampleState(), legend: { ...exampleState().legend, - legendStats: [XYLegendValue.CurrentAndLastValue], + legendStats: [LegendValue.CurrentAndLastValue], }, }; diff --git a/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx b/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx index 487e23e1224b7b..ca99a3a7fd8533 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx @@ -118,7 +118,9 @@ import { AddLayerButton } from './add_layer'; import { LayerSettings } from './layer_settings'; import { IgnoredGlobalFiltersEntries } from '../../shared_components/ignore_global_filter'; import { getColorMappingTelemetryEvents } from '../../lens_ui_telemetry/color_telemetry_helpers'; +import { getLegendStatsTelemetryEvents } from './legend_stats_telemetry_helpers'; import { XYPersistedState, convertToPersistable, convertToRuntime } from './persistence'; +import { shouldDisplayTable } from '../../shared_components/legend/legend_settings_popover'; import { ANNOTATION_MISSING_DATE_HISTOGRAM, LAYER_SETTINGS_IGNORE_GLOBAL_FILTERS, @@ -1062,10 +1064,22 @@ export const getXyVisualization = ({ getTelemetryEventsOnSave(state, prevState) { const dataLayers = getDataLayers(state.layers); const prevLayers = prevState ? getDataLayers(prevState.layers) : undefined; - return dataLayers.flatMap((l) => { + const colorMappingEvents = dataLayers.flatMap((l) => { const prevLayer = prevLayers?.find((prevL) => prevL.layerId === l.layerId); return getColorMappingTelemetryEvents(l.colorMapping, prevLayer?.colorMapping); }); + const legendStatsEvents = getLegendStatsTelemetryEvents( + state.legend.legendStats, + prevState ? prevState.legend.legendStats : undefined + ); + return colorMappingEvents.concat(legendStatsEvents); + }, + + getRenderEventCounters(state) { + if (shouldDisplayTable(state.legend.legendStats ?? [])) { + return [`legend_stats`]; + } + return []; }, }); diff --git a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/axis_settings_popover.test.tsx b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/axis_settings_popover.test.tsx index 1976b8084d7f9e..fbf14216ad7a2b 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/axis_settings_popover.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/axis_settings_popover.test.tsx @@ -39,7 +39,7 @@ describe('AxesSettingsPopover', () => { axis: 'x', areTickLabelsVisible: true, areGridlinesVisible: true, - isAxisTitleVisible: true, + isTitleVisible: true, toggleTickLabelsVisibility: jest.fn(), toggleGridlinesVisibility: jest.fn(), hasBarOrAreaOnAxis: false, diff --git a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/axis_settings_popover.tsx b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/axis_settings_popover.tsx index 1714fc4a4e4066..20390f322fd90c 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/axis_settings_popover.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/xy_config_panel/axis_settings_popover.tsx @@ -21,7 +21,7 @@ import { useDebouncedValue } from '@kbn/visualization-ui-components'; import { isHorizontalChart } from '../state_helpers'; import { ToolbarPopover, - AxisTitleSettings, + ToolbarTitleSettings, AxisBoundsControl, AxisTicksSettings, } from '../../../shared_components'; @@ -51,7 +51,7 @@ export interface AxisSettingsPopoverProps { */ updateTitleState: ( title: { title?: string; visible: boolean }, - axis: AxesSettingsConfigKeys + settingId: AxesSettingsConfigKeys ) => void; /** * Determines if the popover is Disabled @@ -84,7 +84,7 @@ export interface AxisSettingsPopoverProps { /** * Determines if the title visibility switch is on and the input text is disabled */ - isAxisTitleVisible: boolean; + isTitleVisible: boolean; /** * Set endzone visibility */ @@ -224,7 +224,7 @@ export const AxisSettingsPopover: React.FunctionComponent - updateTitleState(title, axis)} + isTitleVisible={isTitleVisible} /> = [ + { + value: LegendValue.Average, + label: i18n.translate('xpack.lens.shared.legendValues.average', { + defaultMessage: 'Average', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.averageDesc', { + defaultMessage: 'Average of all values in the series.', + }), + }, + { + value: LegendValue.Median, + label: i18n.translate('xpack.lens.shared.legendValues.median', { + defaultMessage: 'Median', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.medianDesc', { + defaultMessage: 'Median value in the series.', + }), + }, + { + value: LegendValue.Min, + label: i18n.translate('xpack.lens.shared.legendValues.min', { + defaultMessage: 'Minimum', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.minDesc', { + defaultMessage: 'Minimum value in the series.', + }), + }, + { + value: LegendValue.Max, + label: i18n.translate('xpack.lens.shared.legendValues.max', { + defaultMessage: 'Maximum', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.maxDesc', { + defaultMessage: 'Maximum value in the series.', + }), + }, + { + value: LegendValue.Range, + label: i18n.translate('xpack.lens.shared.legendValues.range', { + defaultMessage: 'Range', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.rangeDesc', { + defaultMessage: 'Difference between the min and the max in the series.', + }), + }, + { + value: LegendValue.LastValue, + label: i18n.translate('xpack.lens.shared.legendValues.lastValue', { + defaultMessage: 'Last value', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.lastValueDesc', { + defaultMessage: 'Last value in the series.', + }), + }, + { + value: LegendValue.LastNonNullValue, + label: i18n.translate('xpack.lens.shared.legendValues.lastNonNullValue', { + defaultMessage: 'Last non-null value', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.lastNonNullValueDesc', { + defaultMessage: 'Last non-null value in the series.', + }), + }, + { + value: LegendValue.FirstValue, + label: i18n.translate('xpack.lens.shared.legendValues.firstValue', { + defaultMessage: 'First value', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.firstValueDesc', { + defaultMessage: 'First value in the series.', + }), + }, + { + value: LegendValue.FirstNonNullValue, + label: i18n.translate('xpack.lens.shared.legendValues.firstNonNullValue', { + defaultMessage: 'First non-null value', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.firstNonNullValueDesc', { + defaultMessage: 'First non-null value in the series.', + }), + }, + { + value: LegendValue.Difference, + label: i18n.translate('xpack.lens.shared.legendValues.diff', { + defaultMessage: 'Difference', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.diffDesc', { + defaultMessage: 'Difference between first and last value in the series.', + }), + }, + { + value: LegendValue.DifferencePercent, + label: i18n.translate('xpack.lens.shared.legendValues.diffPercent', { + defaultMessage: 'Difference %', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.diffPercentDesc', { + defaultMessage: 'Difference in percent between first and last value in the series.', + }), + }, + { + value: LegendValue.Total, + label: i18n.translate('xpack.lens.shared.legendValues.total', { + defaultMessage: 'Sum', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.totalDesc', { + defaultMessage: 'The sum of all values in the series.', + }), + }, + { + value: LegendValue.Count, + label: i18n.translate('xpack.lens.shared.legendValues.count', { + defaultMessage: 'Count', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.countDesc', { + defaultMessage: 'Count of all the values in the series.', + }), + }, + { + value: LegendValue.DistinctCount, + label: i18n.translate('xpack.lens.shared.legendValues.distinctCount', { + defaultMessage: 'Distinct count', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.distinctCountDesc', { + defaultMessage: 'Count of distinct values in the series.', + }), + }, + { + value: LegendValue.Variance, + label: i18n.translate('xpack.lens.shared.legendValues.variance', { + defaultMessage: 'Variance', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.varianceDesc', { + defaultMessage: 'Variance of all the values in the series.', + }), + }, + { + value: LegendValue.StdDeviation, + label: i18n.translate('xpack.lens.shared.legendValues.stdDev', { + defaultMessage: 'Std deviation', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.stdDevDesc', { + defaultMessage: 'Standard deviation of all the values in the series.', + }), + }, + // Moved to the bottom to limit its usage. It could cause some UX issues due to the dynamic nature + // of the data displayed + { + value: LegendValue.CurrentAndLastValue, + label: i18n.translate('xpack.lens.shared.legendValues.currentValue', { + defaultMessage: 'Current or last value', + }), + toolTipContent: i18n.translate('xpack.lens.shared.legendValues.currentValueDesc', { + defaultMessage: + 'Value of the bucket being hovered or the last bucket value when not hovering.', + }), + }, +]; + +const defaultLegendTitle = i18n.translate('xpack.lens.xyChart.legendTitle', { + defaultMessage: 'Legend', +}); + export const XyToolbar = memo(function XyToolbar( props: VisualizationToolbarProps & { useLegacyTimeAxis?: boolean } ) { @@ -209,7 +375,7 @@ export const XyToolbar = memo(function XyToolbar( ); const nonOrdinalXAxis = dataLayers.every( (layer) => - !layer.xAccessor || + layer.xAccessor && getScaleType( props.frame.datasourceLayers[layer.layerId]?.getOperationForColumnId(layer.xAccessor) ?? null, @@ -336,9 +502,6 @@ export const XyToolbar = memo(function XyToolbar( ).truncateText; const legendSize = state.legend.legendSize; - - const [hadAutoLegendSize] = useState(() => legendSize === LegendSize.AUTO); - return ( @@ -362,6 +525,23 @@ export const XyToolbar = memo(function XyToolbar( }, }); }} + titlePlaceholder={ + frame.activeData?.[dataLayers[0].layerId]?.columns.find( + (col) => col.id === dataLayers[0].splitAccessor + )?.name ?? defaultLegendTitle + } + legendTitle={state?.legend.title} + onLegendTitleChange={({ title, visible }) => { + setState({ + ...state, + legend: { + ...state.legend, + title, + isTitleVisible: visible, + }, + }); + }} + isTitleVisible={state?.legend.isTitleVisible} onDisplayChange={(optionId) => { const newMode = legendOptions.find(({ id }) => id === optionId)!.value; if (newMode === 'auto') { @@ -435,14 +615,29 @@ export const XyToolbar = memo(function XyToolbar( legend: { ...state.legend, verticalAlignment, horizontalAlignment }, }); }} - allowLegendStats={nonOrdinalXAxis} + allowedLegendStats={nonOrdinalXAxis ? xyLegendValues : undefined} legendStats={state?.legend.legendStats} - onLegendStatsChange={(checked) => { + onLegendStatsChange={(legendStats, hasConvertedToTable) => { + if (hasConvertedToTable) { + setState({ + ...state, + legend: { + ...state.legend, + legendStats, + legendSize: LegendSize.AUTO, + isVisible: true, + showSingleSeries: true, + }, + }); + return; + } setState({ ...state, legend: { ...state.legend, - legendStats: checked ? [XYLegendValue.CurrentAndLastValue] : [], + legendStats, + isVisible: true, + showSingleSeries: true, }, }); }} @@ -456,7 +651,7 @@ export const XyToolbar = memo(function XyToolbar( }, }); }} - showAutoLegendSizeOption={hadAutoLegendSize} + showAutoLegendSizeOption={true} /> @@ -491,7 +686,7 @@ export const XyToolbar = memo(function XyToolbar( } orientation={labelsOrientation.yLeft} setOrientation={onLabelsOrientationChange} - isAxisTitleVisible={axisTitlesVisibilitySettings.yLeft} + isTitleVisible={axisTitlesVisibilitySettings.yLeft} extent={state?.yLeftExtent || { mode: 'full' }} setExtent={setExtentFn('yLeftExtent')} hasBarOrAreaOnAxis={hasBarOrAreaOnLeftAxis} @@ -514,7 +709,7 @@ export const XyToolbar = memo(function XyToolbar( toggleGridlinesVisibility={onGridlinesVisibilitySettingsChange} orientation={labelsOrientation.x} setOrientation={onLabelsOrientationChange} - isAxisTitleVisible={axisTitlesVisibilitySettings.x} + isTitleVisible={axisTitlesVisibilitySettings.x} endzonesVisible={!state?.hideEndzones} setEndzoneVisibility={onChangeEndzoneVisiblity} currentTimeMarkerVisible={state?.showCurrentTimeMarker} @@ -559,7 +754,7 @@ export const XyToolbar = memo(function XyToolbar( orientation={labelsOrientation.yRight} setOrientation={onLabelsOrientationChange} hasPercentageAxis={hasPercentageAxis(axisGroups, 'right', state)} - isAxisTitleVisible={axisTitlesVisibilitySettings.yRight} + isTitleVisible={axisTitlesVisibilitySettings.yRight} extent={state?.yRightExtent || { mode: 'full' }} setExtent={setExtentFn('yRightExtent')} hasBarOrAreaOnAxis={hasBarOrAreaOnRightAxis} diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 57e13f649a3653..21b3f6e83ac6c3 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -23460,7 +23460,6 @@ "xpack.lens.shared.tickLabels": "Étiquettes de graduation", "xpack.lens.shared.ticksPositionOptions": "Coches sur les bandes", "xpack.lens.shared.ticksPositionOptionsTooltip": "Place les coches sur chaque bordure de bande au lieu de les répartir de manière homogène.", - "xpack.lens.shared.valueInLegendLabel": "Afficher la valeur", "xpack.lens.shared.valueLabelsVisibility.auto": "Masquer", "xpack.lens.shared.valueLabelsVisibility.inside": "Afficher", "xpack.lens.staticValue.headingLabel": "Placement", @@ -44622,4 +44621,4 @@ "xpack.serverlessObservability.nav.projectSettings": "Paramètres de projet", "xpack.serverlessObservability.nav.synthetics": "Synthetics" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 34bfbb83ecfe1d..902b420e0098c6 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -23441,7 +23441,6 @@ "xpack.lens.shared.tickLabels": "目盛ラベル", "xpack.lens.shared.ticksPositionOptions": "帯の目盛", "xpack.lens.shared.ticksPositionOptionsTooltip": "目盛を均等に分布するのではなく、各帯の境界に目盛を表示します", - "xpack.lens.shared.valueInLegendLabel": "値を表示", "xpack.lens.shared.valueLabelsVisibility.auto": "非表示", "xpack.lens.shared.valueLabelsVisibility.inside": "表示", "xpack.lens.staticValue.headingLabel": "配置", @@ -44598,4 +44597,4 @@ "xpack.serverlessObservability.nav.projectSettings": "プロジェクト設定", "xpack.serverlessObservability.nav.synthetics": "Synthetics" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 2b6307f7417bb5..7c3f6e0ecea524 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -23474,7 +23474,6 @@ "xpack.lens.shared.tickLabels": "刻度标签", "xpack.lens.shared.ticksPositionOptions": "带上的刻度", "xpack.lens.shared.ticksPositionOptionsTooltip": "将刻度放在每个带边框上,而不是平均分布", - "xpack.lens.shared.valueInLegendLabel": "显示值", "xpack.lens.shared.valueLabelsVisibility.auto": "隐藏", "xpack.lens.shared.valueLabelsVisibility.inside": "显示", "xpack.lens.staticValue.headingLabel": "位置", @@ -44646,4 +44645,4 @@ "xpack.serverlessObservability.nav.projectSettings": "项目设置", "xpack.serverlessObservability.nav.synthetics": "Synthetics" } -} +} \ No newline at end of file diff --git a/x-pack/test/functional/apps/lens/group6/legend_statistics.ts b/x-pack/test/functional/apps/lens/group6/legend_statistics.ts index c5cf63c92b7bd8..a6e8cf8a865102 100644 --- a/x-pack/test/functional/apps/lens/group6/legend_statistics.ts +++ b/x-pack/test/functional/apps/lens/group6/legend_statistics.ts @@ -26,12 +26,23 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const text = await legendElement.getVisibleText(); expect(text).to.eql(expectedText); } + async function expectLegendTableToHaveText(expectedText: string) { + const legendElement = await find.byCssSelector('.echLegendTable'); + const text = await legendElement.getVisibleText(); + expect(text).to.eql(expectedText); + } - describe('lens persisted and runtime state differences properties', () => { + describe('lens legend statistics', () => { before(async () => { await kibanaServer.importExport.load( 'x-pack/test/functional/fixtures/kbn_archiver/lens/legend_statistics' ); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json' + ); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/lens/default' + ); await kibanaServer.uiSettings.update({ 'timepicker:timeDefaults': '{ "from": "2015-09-18T19:37:13.000Z", "to": "2015-09-22T23:30:30.000Z"}', @@ -39,40 +50,72 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.visualize.gotoVisualizationLandingPage({ forceRefresh: true }); }); - after(async () => { - await kibanaServer.uiSettings.unset('timepicker:timeDefaults'); - }); - describe('xy chart', () => { - it('shows values in legend for legacy valuesInLegend===true property and saves it correctly', async () => { - const title = 'xyValuesInLegendTrue'; - await loadSavedLens(title); - await expectLegendOneItem('Count of records', '2'); - await PageObjects.lens.save(title); - await loadSavedLens(title); - await expectLegendOneItem('Count of records', '2'); - }); + describe('xy chart legend statistics', () => { + it('shows table with legend statistics', async () => { + await loadSavedLens('lnsXYvis'); - it('does not show values in legend for legacy valuesInLegend===false prop', async () => { - await loadSavedLens('xyValuesInLegendFalse'); - await expectLegendOneItem('Count of records'); - }); - it('shows values in legend for legendStats===["values"] prop', async () => { - await loadSavedLens('xyLegendStats'); - await expectLegendOneItem('Count of records', '2'); + await PageObjects.lens.toggleToolbarPopover('lnsLegendButton'); + await PageObjects.lens.selectOptionFromComboBox('lnsLegendStatisticsSelect', [ + 'average', + 'minimum', + 'maximum', + ]); + + const tableText = `Avg +Min +Max +97.220.3.248 +19,755 +19,755 +19,755 +169.228.188.120 +18,994 +18,994 +18,994 +78.83.247.30 +17,246 +17,246 +17,246`; + + await expectLegendTableToHaveText(tableText); }); }); - describe('waffle chart', () => { - it('waffleshows values in legend for legacy valuesInLegend===true property', async () => { - await loadSavedLens('waffleValuesInLegendTrue'); - await expectLegendOneItem('Count of records', '14,003'); + describe('lens persisted and runtime state differences properties', () => { + after(async () => { + await kibanaServer.uiSettings.unset('timepicker:timeDefaults'); }); - it('shows values in legend for legacy showValuesInLegend===false prop', async () => { - await loadSavedLens('waffleValuesInLegendFalse'); - await expectLegendOneItem('Count of records', undefined); + describe('xy chart', () => { + it('shows values in legend for legacy valuesInLegend===true property and saves it correctly', async () => { + const title = 'xyValuesInLegendTrue'; + await loadSavedLens(title); + await expectLegendOneItem('Count of records', '2'); + await PageObjects.lens.save(title); + await loadSavedLens(title); + await expectLegendOneItem('Count of records', '2'); + }); + + it('does not show values in legend for legacy valuesInLegend===false prop', async () => { + await loadSavedLens('xyValuesInLegendFalse'); + await expectLegendOneItem('Count of records'); + }); + it('shows values in legend for legendStats===["values"] prop', async () => { + await loadSavedLens('xyLegendStats'); + await expectLegendOneItem('Count of records', '2'); + }); }); - it('shows values in legend for legendStats===["values"] prop', async () => { - await loadSavedLens('waffleLegendStats'); - await expectLegendOneItem('Count of records', '14,003'); + describe('waffle chart', () => { + it('waffleshows values in legend for legacy valuesInLegend===true property', async () => { + await loadSavedLens('waffleValuesInLegendTrue'); + await expectLegendOneItem('Count of records', '14,003'); + }); + it('shows values in legend for legacy showValuesInLegend===false prop', async () => { + await loadSavedLens('waffleValuesInLegendFalse'); + await expectLegendOneItem('Count of records', undefined); + }); + it('shows values in legend for legendStats===["values"] prop', async () => { + await loadSavedLens('waffleLegendStats'); + await expectLegendOneItem('Count of records', '14,003'); + }); }); }); }); diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 9a5680b8cdf3cd..913396d5b64dc3 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -120,10 +120,13 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont }); }, - async selectOptionFromComboBox(testTargetId: string, name: string) { + async selectOptionFromComboBox(testTargetId: string, name: string | string[]) { const target = await testSubjects.find(testTargetId, 1000); await comboBox.openOptionsList(target); - await comboBox.setElement(target, name); + const names = Array.isArray(name) ? name : [name]; + for (const option of names) { + await comboBox.setElement(target, option); + } }, async configureQueryAnnotation(opts: { From 37426f0bdec3149db9a50cc13c79bccfe3e4e376 Mon Sep 17 00:00:00 2001 From: Gerard Soldevila Date: Thu, 20 Jun 2024 09:19:18 +0200 Subject: [PATCH 106/123] Check compatible `cluster.routing.allocation.enable` only on reindex migrations (#186090) ## Summary Addresses https://github.com/elastic/kibana/issues/177831. The PR introduces specific steps to check that `cluster.routing.allocation.enable` has a suitable value for _reindex migrations_. Up until now, this check was done systematically after the `INIT` step. Now, a couple new dedicated steps have been introduced, which allow verifying this setting on _reindex migrations_ only (highlighted in orange): ![image](https://github.com/elastic/kibana/assets/25349407/07c7f0b4-fa11-4925-908a-3cb222685796) --- .../index.ts | 2 +- .../src/README.md | 740 ++++++++++++++---- ... check_cluster_routing_allocation.test.ts} | 16 +- ...ts => check_cluster_routing_allocation.ts} | 42 +- .../src/actions/index.ts | 6 +- .../src/model/model.test.ts | 402 +++++----- .../src/model/model.ts | 385 ++++----- .../src/next.ts | 5 +- .../src/state.ts | 10 + .../src/zdt/actions/index.ts | 3 +- .../src/zdt/model/model.test.ts | 4 +- .../src/zdt/model/stages/init.test.ts | 114 ++- .../src/zdt/model/stages/init.ts | 13 - .../src/zdt/next.ts | 2 +- .../migrations/group3/actions/actions.test.ts | 34 +- .../group3/actions/actions_test_suite.ts | 34 +- .../migrations/group5/active_delete.test.ts | 5 +- .../group5/dot_kibana_split.test.ts | 6 +- .../migrations/group5/skip_reindex.test.ts | 5 +- 19 files changed, 1168 insertions(+), 660 deletions(-) rename packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/{initialize_action.test.ts => check_cluster_routing_allocation.test.ts} (89%) rename packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/{initialize_action.ts => check_cluster_routing_allocation.ts} (57%) diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/index.ts index 49ae09a16e7bb3..cdb8d29dd725ae 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/index.ts @@ -24,7 +24,6 @@ export { calculateExcludeFilters, checkForUnknownDocs, waitForIndexStatus, - initAction, cloneIndex, waitForTask, updateAndPickupMappings, @@ -40,6 +39,7 @@ export { fetchIndices, waitForReindexTask, waitForPickupUpdatedMappingsTask, + checkClusterRoutingAllocationEnabled, } from './src/actions'; export type { OpenPitResponse, diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/README.md b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/README.md index f30b09fca6212d..ebeea457bb6225 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/README.md +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/README.md @@ -1,95 +1,134 @@ + - [Introduction](#introduction) - [Algorithm steps](#algorithm-steps) - [INIT](#init) - [Next action](#next-action) - [New control state](#new-control-state) - - [CREATE_NEW_TARGET](#create_new_target) + - [CREATE\_NEW\_TARGET](#create_new_target) - [Next action](#next-action-1) - [New control state](#new-control-state-1) - - [LEGACY_SET_WRITE_BLOCK](#legacy_set_write_block) + - [LEGACY\_CHECK\_CLUSTER\_ROUTING\_ALLOCATION](#legacy_check_cluster_routing_allocation) - [Next action](#next-action-2) - [New control state](#new-control-state-2) - - [LEGACY_CREATE_REINDEX_TARGET](#legacy_create_reindex_target) + - [LEGACY\_SET\_WRITE\_BLOCK](#legacy_set_write_block) - [Next action](#next-action-3) - [New control state](#new-control-state-3) - - [LEGACY_REINDEX](#legacy_reindex) + - [LEGACY\_CREATE\_REINDEX\_TARGET](#legacy_create_reindex_target) - [Next action](#next-action-4) - [New control state](#new-control-state-4) - - [LEGACY_REINDEX_WAIT_FOR_TASK](#legacy_reindex_wait_for_task) + - [LEGACY\_REINDEX](#legacy_reindex) - [Next action](#next-action-5) - [New control state](#new-control-state-5) - - [LEGACY_DELETE](#legacy_delete) + - [LEGACY\_REINDEX\_WAIT\_FOR\_TASK](#legacy_reindex_wait_for_task) - [Next action](#next-action-6) - [New control state](#new-control-state-6) - - [WAIT_FOR_MIGRATION_COMPLETION](#wait_for_migration_completion) + - [LEGACY\_DELETE](#legacy_delete) - [Next action](#next-action-7) - [New control state](#new-control-state-7) - - [WAIT_FOR_YELLOW_SOURCE](#wait_for_yellow_source) + - [WAIT\_FOR\_MIGRATION\_COMPLETION](#wait_for_migration_completion) - [Next action](#next-action-8) - [New control state](#new-control-state-8) - - [UPDATE_SOURCE_MAPPINGS_PROPERTIES](#update_source_mappings_properties) + - [WAIT\_FOR\_YELLOW\_SOURCE](#wait_for_yellow_source) - [Next action](#next-action-9) - [New control state](#new-control-state-9) - - [SET_SOURCE_WRITE_BLOCK](#set_source_write_block) + - [UPDATE\_SOURCE\_MAPPINGS\_PROPERTIES](#update_source_mappings_properties) - [Next action](#next-action-10) - [New control state](#new-control-state-10) - - [CREATE_REINDEX_TEMP](#create_reindex_temp) + - [CLEANUP\_UNKNOWN\_AND\_EXCLUDED](#cleanup_unknown_and_excluded) - [Next action](#next-action-11) - [New control state](#new-control-state-11) - - [REINDEX_SOURCE_TO_TEMP_OPEN_PIT](#reindex_source_to_temp_open_pit) + - [CLEANUP\_UNKNOWN\_AND\_EXCLUDED\_WAIT\_FOR\_TASK](#cleanup_unknown_and_excluded_wait_for_task) - [Next action](#next-action-12) - [New control state](#new-control-state-12) - - [REINDEX_SOURCE_TO_TEMP_READ](#reindex_source_to_temp_read) + - [PREPARE\_COMPATIBLE\_MIGRATION](#prepare_compatible_migration) - [Next action](#next-action-13) - [New control state](#new-control-state-13) - - [REINDEX_SOURCE_TO_TEMP_TRANSFORM](#reindex_source_to_temp_transform) + - [REFRESH\_SOURCE](#refresh_source) - [Next action](#next-action-14) - [New control state](#new-control-state-14) - - [REINDEX_SOURCE_TO_TEMP_INDEX_BULK](#reindex_source_to_temp_index_bulk) + - [CHECK\_CLUSTER\_ROUTING\_ALLOCATION](#check_cluster_routing_allocation) - [Next action](#next-action-15) - [New control state](#new-control-state-15) - - [REINDEX_SOURCE_TO_TEMP_CLOSE_PIT](#reindex_source_to_temp_close_pit) + - [CHECK\_UNKNOWN\_DOCUMENTS](#check_unknown_documents) - [Next action](#next-action-16) - - [New control state](#new-control-state-16) - - [SET_TEMP_WRITE_BLOCK](#set_temp_write_block) + - [SET\_SOURCE\_WRITE\_BLOCK](#set_source_write_block) - [Next action](#next-action-17) - - [New control state](#new-control-state-17) - - [CLONE_TEMP_TO_TARGET](#clone_temp_to_target) + - [New control state](#new-control-state-16) + - [CREATE\_REINDEX\_TEMP](#create_reindex_temp) - [Next action](#next-action-18) - - [New control state](#new-control-state-18) - - [OUTDATED_DOCUMENTS_SEARCH](#outdated_documents_search) + - [New control state](#new-control-state-17) + - [REINDEX\_SOURCE\_TO\_TEMP\_OPEN\_PIT](#reindex_source_to_temp_open_pit) - [Next action](#next-action-19) - - [New control state](#new-control-state-19) - - [OUTDATED_DOCUMENTS_TRANSFORM](#outdated_documents_transform) + - [New control state](#new-control-state-18) + - [REINDEX\_SOURCE\_TO\_TEMP\_READ](#reindex_source_to_temp_read) - [Next action](#next-action-20) - - [New control state](#new-control-state-20) - - [CHECK_TARGET_MAPPINGS](#check_target_mappings) + - [New control state](#new-control-state-19) + - [REINDEX\_SOURCE\_TO\_TEMP\_TRANSFORM](#reindex_source_to_temp_transform) - [Next action](#next-action-21) - - [New control state](#new-control-state-21) - - [UPDATE_TARGET_MAPPINGS_PROPERTIES](#update_target_mappings_properties) + - [New control state](#new-control-state-20) + - [REINDEX\_SOURCE\_TO\_TEMP\_INDEX\_BULK](#reindex_source_to_temp_index_bulk) - [Next action](#next-action-22) - - [New control state](#new-control-state-22) - - [UPDATE_TARGET_MAPPINGS_PROPERTIES_WAIT_FOR_TASK](#update_target_mappings_properties_wait_for_task) + - [New control state](#new-control-state-21) + - [REINDEX\_SOURCE\_TO\_TEMP\_CLOSE\_PIT](#reindex_source_to_temp_close_pit) - [Next action](#next-action-23) - - [New control state](#new-control-state-23) - - [CHECK_VERSION_INDEX_READY_ACTIONS](#check_version_index_ready_actions) + - [New control state](#new-control-state-22) + - [SET\_TEMP\_WRITE\_BLOCK](#set_temp_write_block) - [Next action](#next-action-24) - - [New control state](#new-control-state-24) - - [MARK_VERSION_INDEX_READY](#mark_version_index_ready) + - [New control state](#new-control-state-23) + - [CLONE\_TEMP\_TO\_TARGET](#clone_temp_to_target) - [Next action](#next-action-25) - - [New control state](#new-control-state-25) - - [MARK_VERSION_INDEX_READY_CONFLICT](#mark_version_index_ready_conflict) + - [New control state](#new-control-state-24) + - [REFRESH\_TARGET](#refresh_target) - [Next action](#next-action-26) + - [New control state](#new-control-state-25) + - [OUTDATED\_DOCUMENTS\_SEARCH\_OPEN\_PIT](#outdated_documents_search_open_pit) + - [Next action](#next-action-27) - [New control state](#new-control-state-26) + - [OUTDATED\_DOCUMENTS\_SEARCH\_READ](#outdated_documents_search_read) + - [Next action](#next-action-28) + - [New control state](#new-control-state-27) + - [OUTDATED\_DOCUMENTS\_TRANSFORM](#outdated_documents_transform) + - [Next action](#next-action-29) + - [New control state](#new-control-state-28) + - [TRANSFORMED\_DOCUMENTS\_BULK\_INDEX](#transformed_documents_bulk_index) + - [Next action](#next-action-30) + - [New control state](#new-control-state-29) + - [OUTDATED\_DOCUMENTS\_SEARCH\_CLOSE\_PIT](#outdated_documents_search_close_pit) + - [Next action](#next-action-31) + - [New control state](#new-control-state-30) + - [OUTDATED\_DOCUMENTS\_REFRESH](#outdated_documents_refresh) + - [Next action](#next-action-32) + - [New control state](#new-control-state-31) + - [CHECK\_TARGET\_MAPPINGS](#check_target_mappings) + - [Next action](#next-action-33) + - [New control state](#new-control-state-32) + - [UPDATE\_TARGET\_MAPPINGS\_PROPERTIES](#update_target_mappings_properties) + - [Next action](#next-action-34) + - [New control state](#new-control-state-33) + - [UPDATE\_TARGET\_MAPPINGS\_PROPERTIES\_WAIT\_FOR\_TASK](#update_target_mappings_properties_wait_for_task) + - [Next action](#next-action-35) + - [New control state](#new-control-state-34) + - [CHECK\_VERSION\_INDEX\_READY\_ACTIONS](#check_version_index_ready_actions) + - [Next action](#next-action-36) + - [New control state](#new-control-state-35) + - [MARK\_VERSION\_INDEX\_READY](#mark_version_index_ready) + - [Next action](#next-action-37) + - [New control state](#new-control-state-36) + - [MARK\_VERSION\_INDEX\_READY\_CONFLICT](#mark_version_index_ready_conflict) + - [Next action](#next-action-38) + - [New control state](#new-control-state-37) + - [FATAL](#fatal) + - [DONE](#done) - [Manual QA Test Plan](#manual-qa-test-plan) - [1. Legacy pre-migration](#1-legacy-pre-migration) - [2. Plugins enabled/disabled](#2-plugins-enableddisabled) - - [Test scenario 1 (enable a plugin after migration):](#test-scenario-1-enable-a-plugin-after-migration) - - [Test scenario 2 (disable a plugin after migration):](#test-scenario-2-disable-a-plugin-after-migration) - - [Test scenario 3 (multiple instances, enable a plugin after migration):](#test-scenario-3-multiple-instances-enable-a-plugin-after-migration) - - [Test scenario 4 (multiple instances, mixed plugin enabled configs):](#test-scenario-4-multiple-instances-mixed-plugin-enabled-configs) + - [Test scenario 1 (enable a plugin after migration)](#test-scenario-1-enable-a-plugin-after-migration) + - [Test scenario 2 (disable a plugin after migration)](#test-scenario-2-disable-a-plugin-after-migration) + - [Test scenario 3 (multiple instances, enable a plugin after migration)](#test-scenario-3-multiple-instances-enable-a-plugin-after-migration) + - [Test scenario 4 (multiple instances, mixed plugin enabled configs)](#test-scenario-4-multiple-instances-mixed-plugin-enabled-configs) # Introduction + In the past, the risk of downtime caused by Kibana's saved object upgrade migrations have discouraged users from adopting the latest features. v2 migrations aims to solve this problem by minimizing the operational impact on @@ -108,17 +147,18 @@ migrations RFC](https://github.com/elastic/kibana/blob/main/rfcs/text/0013_saved_object_migrations.md). # Algorithm steps + The design goals for the algorithm was to keep downtime below 10 minutes for 100k saved objects while guaranteeing no data loss and keeping steps as simple and explicit as possible. -The algorithm is implemented as a state-action machine based on https://www.microsoft.com/en-us/research/uploads/prod/2016/12/Computation-and-State-Machines.pdf +The algorithm is implemented as a *state-action machine*, based on The state-action machine defines it's behaviour in steps. Each step is a transition from a control state s_i to the contral state s_i+1 caused by an action a_i. -``` +```text s_i -> a_i -> s_i+1 s_i+1 -> a_i+1 -> s_i+2 ``` @@ -129,7 +169,8 @@ response to determine the next state to transition to as defined by the function `model(state, response)`. We can then loosely define a step as: -``` + +```javascript s_i+1 = model(s_i, await next(s_i)()) ``` @@ -138,8 +179,9 @@ terminates such as in the DONE and FATAL control states. What follows is a list of all control states. For each control state the following is described: - - _next action_: the next action triggered by the current control state - - _new control state_: based on the action response, the possible new control states that the machine will transition to + +- *next action*: the next action triggered by the current control state +- *new control state*: based on the action response, the possible new control states that the machine will transition to Since the algorithm runs once for each saved object index the steps below always reference a single saved object index `.kibana`. When Kibana starts up, @@ -147,14 +189,8 @@ all the steps are also repeated for the `.kibana_task_manager` index but this is left out of the description for brevity. ## INIT -### Next action -`initAction` - -Check that replica allocation is enabled from cluster settings (`cluster.routing.allocation.enabled`). Migrations will fail when replica allocation is disabled during the bulk index operation that waits for all active shards. Migrations wait for all active shards to ensure that saved objects are replicated to protect against data loss. -The Elasticsearch documentation mentions switching off replica allocation when restoring a cluster and this is a setting that might be overlooked when a restore is done. Migrations will fail early if replica allocation is incorrectly set to avoid adding a write block to the old index before running into a failure later. - -If replica allocation is set to 'all', the migration continues to fetch the saved object indices: +### Next action `fetchIndices` @@ -163,53 +199,77 @@ and determine whether we’re migrating from a legacy index or a v1 migrations index. ### New control state -1. Two conditions have to be met before migrations begin: - 1. The Elasticsearch shard allocation cluster setting `cluster.routing.allocation.enable` needs to be unset or set to 'all'. When set to 'primaries', 'new_primaries' or 'none', the migration will timeout when waiting for index green status before bulk indexing because the replica cannot be allocated. - As per the Elasticsearch docs https://www.elastic.co/guide/en/elasticsearch/reference/8.2/restart-cluster.html#restart-cluster-rolling when Cloud performs a rolling restart such as during an upgrade, it will temporarily disable shard allocation. Kibana therefore keeps retrying the INIT step to wait for shard allocation to be enabled again. +1. If `.kibana` is pointing to more than one index. - The check only considers persistent and transient settings and does not take static configuration in `elasticsearch.yml` into account since there are no known use cases for doing so. If `cluster.routing.allocation.enable` is configured in `elaticsearch.yml` and not set to the default of 'all', the migration will timeout. Static settings can only be returned from the `nodes/info` API. - → `INIT` + → [FATAL](#fatal) - 2. If `.kibana` is pointing to more than one index. - → `FATAL` - - 3. If `.kibana` is pointing to an index that belongs to a later version of +2. If `.kibana` is pointing to an index that belongs to a later version of Kibana .e.g. a 7.11.0 instance found the `.kibana` alias pointing to `.kibana_7.12.0_001` fail the migration - → `FATAL` -2. If `waitForMigrations` was set we're running on a background-tasks node and + → [FATAL](#fatal) + +3. If `waitForMigrations` was set we're running on a background-tasks node and we should not participate in the migration but instead wait for the ui node(s) to complete the migration. - → `WAIT_FOR_MIGRATION_COMPLETION` -3. If the `.kibana` alias exists we’re migrating from either a v1 or v2 index + → [WAIT_FOR_MIGRATION_COMPLETION](#wait_for_migration_completion) + +4. If the `.kibana` alias exists we’re migrating from either a v1 or v2 index and the migration source index is the index the `.kibana` alias points to. - → `WAIT_FOR_YELLOW_SOURCE` -4. If `.kibana` is a concrete index, we’re migrating from a legacy index - → `LEGACY_SET_WRITE_BLOCK` + → [WAIT_FOR_YELLOW_SOURCE](#wait_for_yellow_source) + +5. If `.kibana` is a concrete index, we’re migrating from a legacy index + + → [LEGACY_SET_WRITE_BLOCK](#legacy_set_write_block) -5. If there are no `.kibana` indices, this is a fresh deployment. Initialize a +6. If there are no `.kibana` indices, this is a fresh deployment. Initialize a new saved objects index - → `CREATE_NEW_TARGET` + + → [CREATE_NEW_TARGET](#create_new_target) ## CREATE_NEW_TARGET + ### Next action + `createIndex` Create the target index. This operation is idempotent, if the index already exist, we wait until its status turns green ### New control state + 1. If the action succeeds - → `MARK_VERSION_INDEX_READY` + + → [MARK_VERSION_INDEX_READY](#mark_version_index_ready) + 2. If the action fails with a `index_not_green_timeout` - → `CREATE_NEW_TARGET` + → [CREATE_NEW_TARGET](#create_new_target) + +## LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION + +### Next action + +`checkClusterRoutingAllocationCompatible` + +Same description and behavior as [CHECK\_CLUSTER\_ROUTING\_ALLOCATION](#check_cluster_routing_allocation), for legacy flow. + +### New control state + +1. If `cluster.routing.allocation.enabled` has a compatible value. + + → [LEGACY_SET_WRITE_BLOCK](#legacy_set_write_block) + +2. If it has a value that will not allow creating new *saved object* indices. + + → [LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION](#legacy_check_cluster_routing_allocation) (retry) ## LEGACY_SET_WRITE_BLOCK + ### Next action + `setWriteBlock` Set a write block on the legacy index to prevent any older Kibana instances @@ -217,118 +277,312 @@ from writing to the index while the migration is in progress which could cause lost acknowledged writes. This is the first of a series of `LEGACY_*` control states that will: - - reindex the concrete legacy `.kibana` index into a `.kibana_pre6.5.0_001` index - - delete the concrete `.kibana` _index_ so that we're able to create a `.kibana` _alias_ + +- reindex the concrete legacy `.kibana` index into a `.kibana_pre6.5.0_001` index +- delete the concrete `.kibana` *index* so that we're able to create a `.kibana` *alias* ### New control state + 1. If the write block was successfully added - → `LEGACY_CREATE_REINDEX_TARGET` + + → [LEGACY_CREATE_REINDEX_TARGET](#legacy_create_reindex_target) + 2. If the write block failed because the index doesn't exist, it means another instance already completed the legacy pre-migration. Proceed to the next step. - → `LEGACY_CREATE_REINDEX_TARGET` + + → [LEGACY_CREATE_REINDEX_TARGET](#legacy_create_reindex_target) ## LEGACY_CREATE_REINDEX_TARGET + ### Next action + `createIndex` Create a new `.kibana_pre6.5.0_001` index into which we can reindex the legacy index. (Since the task manager index was converted from a data index into a saved objects index in 7.4 it will be reindexed into `.kibana_pre7.4.0_001`) + ### New control state + 1. If the index creation succeeds - → `LEGACY_REINDEX` + + → [LEGACY_REINDEX](#legacy_reindex) + 2. If the index creation task failed with a `index_not_green_timeout` - → `LEGACY_REINDEX_WAIT_FOR_TASK` + + → [LEGACY_REINDEX_WAIT_FOR_TASK](#legacy_reindex_wait_for_task) + ## LEGACY_REINDEX + ### Next action + `reindex` Let Elasticsearch reindex the legacy index into `.kibana_pre6.5.0_001`. (For the task manager index we specify a `preMigrationScript` to convert the original task manager documents into valid saved objects) + ### New control state - → `LEGACY_REINDEX_WAIT_FOR_TASK` +→ [LEGACY_REINDEX_WAIT_FOR_TASK](#legacy_reindex_wait_for_task) ## LEGACY_REINDEX_WAIT_FOR_TASK + ### Next action + `waitForReindexTask` Wait for up to 60s for the reindex task to complete. + ### New control state + 1. If the reindex task completed - → `LEGACY_DELETE` + + → [LEGACY_DELETE](#legacy_delete) + 2. If the reindex task failed with a `target_index_had_write_block` or `index_not_found_exception` another instance already completed this step - → `LEGACY_DELETE` + + → [LEGACY_DELETE](#legacy_delete) + 3. If the reindex task is still in progress - → `LEGACY_REINDEX_WAIT_FOR_TASK` + + → [LEGACY_REINDEX_WAIT_FOR_TASK](#legacy_reindex_wait_for_task) ## LEGACY_DELETE + ### Next action + `updateAliases` Use the updateAliases API to atomically remove the legacy index and create a new `.kibana` alias that points to `.kibana_pre6.5.0_001`. + ### New control state + 1. If the action succeeds - → `SET_SOURCE_WRITE_BLOCK` + + → [SET_SOURCE_WRITE_BLOCK](#set_source_write_block) + 2. If the action fails with `remove_index_not_a_concrete_index` or `index_not_found_exception` another instance has already completed this step. - → `SET_SOURCE_WRITE_BLOCK` + + → [SET_SOURCE_WRITE_BLOCK](#set_source_write_block) ## WAIT_FOR_MIGRATION_COMPLETION + ### Next action + `fetchIndices` + ### New control state + 1. If the ui node finished the migration - → `DONE` + + → [DONE](#done) + 2. Otherwise wait 2s and check again - → `WAIT_FOR_MIGRATION_COMPLETION` + + → [WAIT_FOR_MIGRATION_COMPLETION](#wait_for_migration_completion) ## WAIT_FOR_YELLOW_SOURCE + ### Next action + `waitForIndexStatus` (status='yellow') Wait for the source index to become yellow. This means the index's primary has been allocated and is ready for reading/searching. On a multi node cluster the replicas for this index might not be ready yet but since we're never writing to the source index it does not matter. ### New control state + 1. If the action succeeds - → `UPDATE_SOURCE_MAPPINGS_PROPERTIES` + + → [UPDATE_SOURCE_MAPPINGS_PROPERTIES](#update_source_mappings_properties) + 2. If the action fails with a `index_not_yellow_timeout` - → `WAIT_FOR_YELLOW_SOURCE` + + → [WAIT_FOR_YELLOW_SOURCE](#wait_for_yellow_source) ## UPDATE_SOURCE_MAPPINGS_PROPERTIES + ### Next action + `updateSourceMappingsProperties` This action checks for source mappings changes. And if there are some, it tries to patch the mappings. + - If there were no changes or the patch was successful, that reports either the changes are compatible or the source is already up to date, depending on the version migration completion state. Either way, it does not require a follow-up reindexing. - If the patch is failed and the version migration is incomplete, it reports an incompatible state that requires reindexing. - If the patch is failed and the version migration is complete, it reports an error as it means an incompatible mappings change in an already migrated environment. The latter usually happens when a new plugin is enabled that brings some incompatible changes or when there are incompatible changes in the development environment. ### New control state + 1. If the mappings are updated and the migration is already completed. - → `OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT` + + → [OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT](#outdated_documents_search_open_pit) + 2. If the mappings are updated and the migration is still in progress. - → `CLEANUP_UNKNOWN_AND_EXCLUDED` + + → [CLEANUP_UNKNOWN_AND_EXCLUDED](#cleanup_unknown_and_excluded) + 3. If the mappings are not updated due to incompatible changes and the migration is still in progress. - → `CHECK_UNKNOWN_DOCUMENTS` + + → [CHECK_CLUSTER_ROUTING_ALLOCATION](#check_cluster_routing_allocation) + 4. If the mappings are not updated due to incompatible changes and the migration is already completed. - → `FATAL` + + → [FATAL](#fatal) + +## CLEANUP_UNKNOWN_AND_EXCLUDED + +### Next action + +`cleanupUnknownAndExcluded` + +This action searches for and deletes *saved objects* which are of unknown or excluded type. + +- Saved objects become unknown when their type is no longer registered in the *typeRegistry*. This can happen when disabling plugins. +- Also, saved objects can be excluded from upgrade with the `excludeOnUpgrade` flag in their type definition. + +In order to allow Kibana to discard unknown saved objects, users must set the [migrations.discardUnknownObjects](https://www.elastic.co/guide/en/kibana/current/resolve-migrations-failures.html#unknown-saved-object-types) flag. + +### New control state + +1. If unknown docs are found and Kibana is not configured to ignore them. + + → [FATAL](#fatal) + +2. If the delete operation is launched and we can wait for it. + + → [CLEANUP_UNKNOWN_AND_EXCLUDED_WAIT_FOR_TASK](#cleanup_unknown_and_excluded_wait_for_task) + +## CLEANUP_UNKNOWN_AND_EXCLUDED_WAIT_FOR_TASK + +### Next action + +`waitForDeleteByQueryTask` + +The cleanup task on the previous step is launched asynchronously, tracked by a specific `taskId`. On this step, we actively wait for it to finish, and we do that with a large timeout. + +### New control state + +1. If the task finishes before the timeout. + + → [PREPARE_COMPATIBLE_MIGRATION](#prepare_compatible_migration) + +2. If we hit the timeout whilst waiting for the task to be completed, but we still have some retry attempts left. + + → [CLEANUP_UNKNOWN_AND_EXCLUDED_WAIT_FOR_TASK](#cleanup_unknown_and_excluded_wait_for_task) + +3. If some errors occur whilst cleaning up, there could be other instances performing the cleanup in parallel, deleting the documents that we intend to delete. In that scenario, we will launch the operation again. + + → [CLEANUP_UNKNOWN_AND_EXCLUDED](#cleanup_unknown_and_excluded) + +4. If we hit the timeout and we run out of retries. + + → [FATAL](#fatal) + +## PREPARE_COMPATIBLE_MIGRATION + +### Next action + +`updateAliases` + +At this point, we have successfully updated the index mappings. We are performing a *compatible migration*, aka updating *saved objects* in place on the existing index. In order to prevent other Kibana instances from writing documents whilst we update them, we remove the previous version alias. We also set set the current version alias, which will cause other instances' migrators to directly perform an *up-to-date migration*. + +### New control state + +1. If the aliases are updated successfully and some documents have been deleted on the previous step. + + → [REFRESH_SOURCE](#refresh_source) + +2. If the aliases are updated successfully and we did not delete any documents on the previous step. + + → [OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT](#outdated_documents_search_open_pit) + +3. When unexpected errors occur when updating the aliases. + + → [FATAL](#fatal) + +## REFRESH_SOURCE + +### Next action + +`refreshIndex` + +We are performing a *compatible migration*, and we discarded some unknown and excluded saved object documents. We must refresh the index so that subsequent queries no longer find these removed documents. + +### New control state + +1. If the index is refreshed successfully. + + → [OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT](#outdated_documents_search_open_pit) + +2. When unexpected errors occur during the refresh. + + → [FATAL](#fatal) + +## CHECK_CLUSTER_ROUTING_ALLOCATION + +### Next action + +`checkClusterRoutingAllocationEnabled` + +Check that replica allocation is enabled from cluster settings (`cluster.routing.allocation.enabled`). Migrations will fail when replica allocation is disabled during the bulk index operation that waits for all active shards. Migrations wait for all active shards to ensure that saved objects are replicated to protect against data loss. + +The Elasticsearch documentation mentions switching off replica allocation when restoring a cluster and this is a setting that might be overlooked when a restore is done. Migrations will fail early if replica allocation is incorrectly set to avoid adding a write block to the old index before running into a failure later. + +If replica allocation is set to 'all', the migration continues to fetch the saved object indices. + +### New control state + +The Elasticsearch shard allocation cluster setting `cluster.routing.allocation.enable` needs to be unset or set to 'all'. When set to 'primaries', 'new_primaries' or 'none', the migration will timeout when waiting for index green status before bulk indexing because the replica cannot be allocated. + +As per the Elasticsearch [docs](https://www.elastic.co/guide/en/elasticsearch/reference/8.2/restart-cluster.html#restart-cluster-rolling), when Cloud performs a rolling restart such as during an upgrade, it will temporarily disable shard allocation. Kibana therefore keeps retrying the INIT step to wait for shard allocation to be enabled again. + +The check only considers persistent and transient settings and does not take static configuration in `elasticsearch.yml` into account since there are no known use cases for doing so. If `cluster.routing.allocation.enable` is configured in `elaticsearch.yml` and not set to the default of 'all', the migration will timeout. Static settings can only be returned from the `nodes/info` API. + +1. If `cluster.routing.allocation.enabled` has a compatible value. + + → [CHECK_UNKNOWN_DOCUMENTS](#check_unknown_documents) + +2. If it has a value that will not allow creating new *saved object* indices. + + → [CHECK_CLUSTER_ROUTING_ALLOCATION](#check_cluster_routing_allocation) (retry) + +## CHECK_UNKNOWN_DOCUMENTS + +Saved objects are unknown when their type is not registered in the *typeRegistry*. This can happen when disabling plugins, or when deprecated plugins are removed during a major upgrade. + +During a *reindex migration*, these documents can be discarded if Kibana is configured with the [migrations.discardUnknownObjects](https://www.elastic.co/guide/en/kibana/current/resolve-migrations-failures.html#unknown-saved-object-types) flag. + +### Next action + +1. If no unknown documents are found, or Kibana is configured to discard them. + + → [SET_SOURCE_WRITE_BLOCK](#set_source_write_block) + +2. If some unknown documents are found and Kibana is NOT configured to discard them. + + → [FATAL](#fatal) ## SET_SOURCE_WRITE_BLOCK + ### Next action + `setWriteBlock` Set a write block on the source index to prevent any older Kibana instances from writing to the index while the migration is in progress which could cause lost acknowledged writes. ### New control state - → `CREATE_REINDEX_TEMP` + +→ [CREATE_REINDEX_TEMP](#create_reindex_temp) ## CREATE_REINDEX_TEMP + ### Next action + `createIndex` This operation is idempotent, if the index already exist, we wait until its status turns green. @@ -337,33 +591,49 @@ This operation is idempotent, if the index already exist, we wait until its stat - (Since we never query the temporary index we can potentially disable refresh to speed up indexing performance. Profile to see if gains justify complexity) ### New control state + 1. If the action succeeds - → `REINDEX_SOURCE_TO_TEMP_OPEN_PIT` + + → [REINDEX_SOURCE_TO_TEMP_OPEN_PIT](#reindex_source_to_temp_open_pit) + 2. If the action fails with a `index_not_green_timeout` - → `CREATE_REINDEX_TEMP` + + → [CREATE_REINDEX_TEMP](#create_reindex_temp) ## REINDEX_SOURCE_TO_TEMP_OPEN_PIT + ### Next action + `openPIT` Open a PIT. Since there is a write block on the source index there is basically no overhead to keeping the PIT so we can lean towards a larger `keep_alive` value like 10 minutes. + ### New control state - → `REINDEX_SOURCE_TO_TEMP_READ` + +→ [REINDEX_SOURCE_TO_TEMP_READ](#reindex_source_to_temp_read) ## REINDEX_SOURCE_TO_TEMP_READ + ### Next action + `readNextBatchOfSourceDocuments` Read the next batch of outdated documents from the source index by using search after with our PIT. ### New control state + 1. If the batch contained > 0 documents - → `REINDEX_SOURCE_TO_TEMP_TRANSFORM` + + → [REINDEX_SOURCE_TO_TEMP_TRANSFORM](#reindex_source_to_temp_transform) + 2. If there are no more documents returned - → `REINDEX_SOURCE_TO_TEMP_CLOSE_PIT` + + → [REINDEX_SOURCE_TO_TEMP_CLOSE_PIT](#reindex_source_to_temp_close_pit) ## REINDEX_SOURCE_TO_TEMP_TRANSFORM + ### Next action + `transformRawDocs` Transform the current batch of documents @@ -372,10 +642,15 @@ In order to support sharing saved objects to multiple spaces in 8.0, the transforms will also regenerate document `_id`'s. To ensure that this step remains idempotent, the new `_id` is deterministically generated using UUIDv5 ensuring that each Kibana instance generates the same new `_id` for the same document. + ### New control state - → `REINDEX_SOURCE_TO_TEMP_INDEX_BULK` + +→ [REINDEX_SOURCE_TO_TEMP_INDEX_BULK](#reindex_source_to_temp_index_bulk) + ## REINDEX_SOURCE_TO_TEMP_INDEX_BULK + ### Next action + `bulkIndexTransformedDocuments` Use the bulk API create action to write a batch of up-to-date documents. The @@ -386,32 +661,47 @@ step will ensure that the index is refreshed before we start serving traffic. The following errors are ignored because it means another instance already completed this step: - - documents already exist in the temp index - - temp index has a write block - - temp index is not found + +- documents already exist in the temp index +- temp index has a write block +- temp index is not found + ### New control state + 1. If `currentBatch` is the last batch in `bulkOperationBatches` - → `REINDEX_SOURCE_TO_TEMP_READ` + + → [REINDEX_SOURCE_TO_TEMP_READ](#reindex_source_to_temp_read) + 2. If there are more batches left in `bulkOperationBatches` - → `REINDEX_SOURCE_TO_TEMP_INDEX_BULK` + + → [REINDEX_SOURCE_TO_TEMP_INDEX_BULK](#reindex_source_to_temp_index_bulk) ## REINDEX_SOURCE_TO_TEMP_CLOSE_PIT + ### Next action + `closePIT` ### New control state - → `SET_TEMP_WRITE_BLOCK` + +→ [SET_TEMP_WRITE_BLOCK](#set_temp_write_block) ## SET_TEMP_WRITE_BLOCK + ### Next action + `setWriteBlock` Set a write block on the temporary index so that we can clone it. + ### New control state - → `CLONE_TEMP_TO_TARGET` + +→ [CLONE_TEMP_TO_TARGET](#clone_temp_to_target) ## CLONE_TEMP_TO_TARGET + ### Next action + `cloneIndex` Ask elasticsearch to clone the temporary index into the target index. If the target index already exists (because another node already started the clone operation), wait until the clone is complete by waiting for a green index status. @@ -419,13 +709,56 @@ Ask elasticsearch to clone the temporary index into the target index. If the tar We can’t use the temporary index as our target index because one instance can complete the migration, delete a document, and then a second instance starts the reindex operation and re-creates the deleted document. By cloning the temporary index and only accepting writes/deletes from the cloned target index, we prevent lost acknowledged deletes. ### New control state -1. If the action succeeds - → `OUTDATED_DOCUMENTS_SEARCH` -2. If the action fails with a `index_not_green_timeout` - → `CLONE_TEMP_TO_TARGET` -## OUTDATED_DOCUMENTS_SEARCH +1. If the action succeeds. + + → [REFRESH_TARGET](#refresh_target) + +2. If the action fails with an `index_not_green_timeout`. + + → [CLONE_TEMP_TO_TARGET](#clone_temp_to_target) + +## REFRESH_TARGET + +### Next action + +`refreshIndex` + +We refresh the temporary clone index, to make sure newly added documents are taken into account. + +### New control state + +1. If the index is refreshed successfully. + + → [OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT](#outdated_documents_search_open_pit) + +2. When unexpected errors occur during the refresh. + + → [FATAL](#fatal) + +## OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT + +### Next action + +`openPit` + +Any saved objects that belong to previous versions are updated in the index. +This operation is performed in batches, leveraging the [Point in Time API](https://www.elastic.co/guide/en/elasticsearch/reference/current/point-in-time-api.html). + +### New control state + +1. If the PIT is created successfully. + + → [OUTDATED_DOCUMENTS_SEARCH_READ](#outdated_documents_search_read) + +2. When unexpected errors occur whilst creating the PIT. + + → [FATAL](#fatal) + +## OUTDATED_DOCUMENTS_SEARCH_READ + ### Next action + `readWithPit(outdatedDocumentsQuery)` Search for outdated saved object documents. Will return one batch of @@ -438,19 +771,100 @@ plugins were disabled by the instance that performed the and transform them to ensure that everything is up to date. ### New control state -1. Found outdated documents? - → `OUTDATED_DOCUMENTS_TRANSFORM` -2. All documents up to date - → `UPDATE_TARGET_MAPPINGS_PROPERTIES` + +1. Found outdated documents. + + → [OUTDATED_DOCUMENTS_TRANSFORM](#outdated_documents_transform) + +2. There aren't any outdated documents left to read, and we can proceed with the flow. + + → [OUTDATED_DOCUMENTS_SEARCH_CLOSE_PIT](#outdated_documents_search_close_pit) + +3. There aren't any outdated documents left to read, but we encountered *corrupt* documents or *transform errors*, and Kibana is not configured to ignore them (using `migrations.discardCorruptObjects` flag). + + → [FATAL](#fatal) + +4. If we encounter an error of the form `es_response_too_large` whilst reading *saved object* documents, we retry with a smaller batch size. + + → [OUTDATED_DOCUMENTS_SEARCH_READ](#outdated_documents_search_read) ## OUTDATED_DOCUMENTS_TRANSFORM + +### Next action + +`transformDocs` + +### New control state + +1. If all of the outdated documents in the current batch are transformed successfully, or Kibana is configured to ignore *corrupt* documents and *transform* errors. We managed to break down the current set of documents into smaller batches successfully, so we can start indexing them one by one. + + → [TRANSFORMED_DOCUMENTS_BULK_INDEX](#transformed_documents_bulk_index) + +2. If the batch contains corrupt documents or transform errors, and Kibana is not configured to discard them, we do not index them, we simply read the next batch, accumulating encountered errors. + + → [OUTDATED_DOCUMENTS_SEARCH_READ](#outdated_documents_search_read) + +3. If we can't split the set of documents in batches small enough to not exceed the `maxBatchSize`, we fail the migration. + + → [FATAL](#fatal) + +## TRANSFORMED_DOCUMENTS_BULK_INDEX + +### Next action + +`bulkOverwriteTransformedDocuments` + +Once transformed we use an index operation to overwrite the outdated document with the up-to-date version. Optimistic concurrency control ensures that we only overwrite the document once so that any updates/writes by another instance which already completed the migration aren’t overwritten and lost. The transformed documents are split in different batches, and then each batch is bulk indexed. + +### New control state + +1. We have more batches to bulk index. + + → [TRANSFORMED_DOCUMENTS_BULK_INDEX](#transformed_documents_bulk_index) + +2. We have indexed all the batches of the current read operation. Proceed to read more documents. + + → [OUTDATED_DOCUMENTS_SEARCH_READ](#outdated_documents_search_read) + +## OUTDATED_DOCUMENTS_SEARCH_CLOSE_PIT + +### Next action + +`closePit` + +After reading, transforming and bulk indexingn all saved objects, we can close our PIT. + +### New control state + +1. If we can close the PIT successfully, and we did update some documents. + + → [OUTDATED_DOCUMENTS_REFRESH](#outdated_documents_refresh) + +2. If we can close the PIT successfully, and we did not update any documents. + + → [CHECK_TARGET_MAPPINGS](#check_target_mappings) + +3. An unexpected error occurred whilst closing the PIT. + + → [FATAL](#fatal) + +## OUTDATED_DOCUMENTS_REFRESH + ### Next action -`transformRawDocs` + `bulkOverwriteTransformedDocuments` -Once transformed we use an index operation to overwrite the outdated document with the up-to-date version. Optimistic concurrency control ensures that we only overwrite the document once so that any updates/writes by another instance which already completed the migration aren’t overwritten and lost. +`refreshIndex` + +We updated some outdated documents, we must refresh the target index to pick up the changes. ### New control state - → `OUTDATED_DOCUMENTS_SEARCH` + +1. If the index is refreshed successfully. + + → [CHECK_TARGET_MAPPINGS](#check_target_mappings) + +2. When unexpected errors occur during the refresh.**** + + → [FATAL](#fatal) ## CHECK_TARGET_MAPPINGS @@ -463,26 +877,35 @@ Compare the calculated mappings' hashes against those stored in the `.map ### New control state 1. If calculated mappings don't match, we must update them. - → `UPDATE_TARGET_MAPPINGS_PROPERTIES` + + → [UPDATE_TARGET_MAPPINGS_PROPERTIES](#update_target_mappings_properties) + 2. If calculated mappings and stored mappings match, we can skip directly to the next step. - → `CHECK_VERSION_INDEX_READY_ACTIONS` + + → [CHECK_VERSION_INDEX_READY_ACTIONS](#check_version_index_ready_actions) ## UPDATE_TARGET_MAPPINGS_PROPERTIES + ### Next action + `updateAndPickupMappings` If another instance has some plugins disabled it will disable the mappings of that plugin's types when creating the temporary index. This action will update the mappings and then use an update_by_query to ensure that all fields are “picked-up” and ready to be searched over. ### New control state - → `UPDATE_TARGET_MAPPINGS_PROPERTIES_WAIT_FOR_TASK` + +→ [UPDATE_TARGET_MAPPINGS_PROPERTIES_WAIT_FOR_TASK](#update_target_mappings_properties_wait_for_task) ## UPDATE_TARGET_MAPPINGS_PROPERTIES_WAIT_FOR_TASK + ### Next action + `waitForPickupUpdatedMappingsTask` ### New control state - → `MARK_VERSION_INDEX_READY` + +→ [MARK_VERSION_INDEX_READY](#mark_version_index_ready) ## CHECK_VERSION_INDEX_READY_ACTIONS @@ -495,12 +918,17 @@ None ### New control state 1. If there are some `versionIndexReadyActions`, we performed a full migration and need to point the aliases to our newly migrated index. - → `MARK_VERSION_INDEX_READY` + + → [MARK_VERSION_INDEX_READY](#mark_version_index_ready) + 2. If there are no `versionIndexReadyActions`, another instance already completed this migration and we only transformed outdated documents and updated the mappings for in case a new plugin was enabled. - → `DONE` + + → [DONE](#done) ## MARK_VERSION_INDEX_READY + ### Next action + `updateAliases` Atomically apply the `versionIndexReadyActions` using the _alias actions API. By performing the following actions we guarantee that if multiple versions of Kibana started the upgrade in parallel, only one version will succeed. @@ -510,40 +938,62 @@ Atomically apply the `versionIndexReadyActions` using the _alias actions API. By 3. Remove the temporary index ### New control state + 1. If all the actions succeed we’re ready to serve traffic - → `DONE` + + → [DONE](#done) + 2. If action (1) fails with alias_not_found_exception or action (3) fails with index_not_found_exception another instance already completed the migration - → `MARK_VERSION_INDEX_READY_CONFLICT` + + → [MARK_VERSION_INDEX_READY_CONFLICT](#mark_version_index_ready_conflict) ## MARK_VERSION_INDEX_READY_CONFLICT + ### Next action + `fetchIndices` Fetch the saved object indices ### New control state + If another instance completed a migration from the same source we need to verify that it is running the same version. 1. If the current and version aliases are pointing to the same index the instance that completed the migration was on the same version and it’s safe to start serving traffic. - → `DONE` + + → [DONE](#done) + 2. If the other instance was running a different version we fail the migration. Once we restart one of two things can happen: the other instance is an older version and we will restart the migration, or, it’s a newer version and we will refuse to start up. - → `FATAL` + + → [FATAL](#fatal) + +## FATAL + +Unfortunately, this migrator failed at some step. Please check the logs and identify the cause. Once addressed, restart Kibana again to restart / resume the migration. + +## DONE + +Congratulations, this migrator finished the saved objects migration for its index. # Manual QA Test Plan + ## 1. Legacy pre-migration + When upgrading from a legacy index additional steps are required before the regular migration process can start. We have the following potential legacy indices: - - v5.x index that wasn't upgraded -> kibana should refuse to start the migration - - v5.x index that was upgraded to v6.x: `.kibana-6` _index_ with `.kibana` _alias_ - - < v6.5 `.kibana` _index_ (Saved Object Migrations were - introduced in v6.5 https://github.com/elastic/kibana/pull/20243) - - TODO: Test versions which introduced the `kibana_index_template` template? - - < v7.4 `.kibana_task_manager` _index_ (Task Manager started - using Saved Objects in v7.4 https://github.com/elastic/kibana/pull/39829) + +- v5.x index that wasn't upgraded -> kibana should refuse to start the migration +- v5.x index that was upgraded to v6.x: `.kibana-6` *index* with `.kibana` *alias* +- < v6.5 `.kibana` *index* (Saved Object Migrations were + introduced in v6.5 ) +- TODO: Test versions which introduced the `kibana_index_template` template? +- < v7.4 `.kibana_task_manager` *index* (Task Manager started + using Saved Objects in v7.4 ) Test plan: + 1. Ensure that the different versions of Kibana listed above can successfully upgrade to 7.11. 2. Ensure that multiple Kibana nodes can migrate a legacy index in parallel @@ -565,6 +1015,7 @@ Test plan: successfully complete the migration. For a successful migration the following behaviour should be observed: + 1. The `.kibana` index should be reindexed into a `.kibana_pre6.5.0` index 2. The `.kibana` index should be deleted 3. The `.kibana_index_template` should be deleted @@ -574,11 +1025,13 @@ For a successful migration the following behaviour should be observed: aliases should point to the `.kibana_7.11.0_001` index. ## 2. Plugins enabled/disabled + Kibana plugins can be disabled/enabled at any point in time. We need to ensure that Saved Object documents are migrated for all the possible sequences of enabling, disabling, before or after a version upgrade. -### Test scenario 1 (enable a plugin after migration): +### Test scenario 1 (enable a plugin after migration) + 1. Start an old version of Kibana (< 7.11) 2. Create a document that we know will be migrated in a later version (i.e. create a `dashboard`) @@ -589,23 +1042,27 @@ enabling, disabling, before or after a version upgrade. 7. Ensure that the document from step (2) has been migrated (`migrationVersion` contains 7.11.0) -### Test scenario 2 (disable a plugin after migration): +### Test scenario 2 (disable a plugin after migration) + 1. Start an old version of Kibana (< 7.11) 2. Create a document that we know will be migrated in a later version (i.e. create a `dashboard`) 3. Upgrade Kibana to v7.11 making sure the plugin in step (3) is enabled. 4. Disable the plugin to which the document belongs (i.e `dashboard` plugin) -6. Restart Kibana -7. Ensure that Kibana logs a warning, but continues to start even though there +5. Restart Kibana +6. Ensure that Kibana logs a warning, but continues to start even though there are saved object documents which don't belong to an enable plugin -### Test scenario 3 (multiple instances, enable a plugin after migration): +### Test scenario 3 (multiple instances, enable a plugin after migration) + Follow the steps from 'Test scenario 1', but perform the migration with multiple instances of Kibana -### Test scenario 4 (multiple instances, mixed plugin enabled configs): +### Test scenario 4 (multiple instances, mixed plugin enabled configs) + We don't support this upgrade scenario, but it's worth making sure we don't have data loss when there's a user error. + 1. Start an old version of Kibana (< 7.11) 2. Create a document that we know will be migrated in a later version (i.e. create a `dashboard`) @@ -615,3 +1072,4 @@ have data loss when there's a user error. other half. 5. Ensure that the document from step (2) has been migrated (`migrationVersion` contains 7.11.0) + diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/check_cluster_routing_allocation.test.ts similarity index 89% rename from packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.test.ts rename to packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/check_cluster_routing_allocation.test.ts index 04ddcd3b78ce50..bce12671db8e4f 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/check_cluster_routing_allocation.test.ts @@ -10,19 +10,13 @@ import * as Either from 'fp-ts/lib/Either'; import { catchRetryableEsClientErrors } from './catch_retryable_es_client_errors'; import { errors as EsErrors } from '@elastic/elasticsearch'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; -import { initAction, type InitActionParams } from './initialize_action'; +import { checkClusterRoutingAllocationEnabled } from './check_cluster_routing_allocation'; jest.mock('./catch_retryable_es_client_errors'); -describe('initAction', () => { - let initActionParams: Omit; - +describe('checkClusterRoutingAllocationEnabled', () => { beforeEach(() => { jest.clearAllMocks(); - - initActionParams = { - indices: ['.kibana', '.kibana_8.8.0'], - }; }); it('calls catchRetryableEsClientErrors when the promise rejects', async () => { const retryableError = new EsErrors.ResponseError( @@ -34,7 +28,7 @@ describe('initAction', () => { const client = elasticsearchClientMock.createInternalClient( elasticsearchClientMock.createErrorTransportRequestPromise(retryableError) ); - const task = initAction({ ...initActionParams, client }); + const task = checkClusterRoutingAllocationEnabled(client); try { await task(); } catch (e) { @@ -62,7 +56,7 @@ describe('initAction', () => { const client = elasticsearchClientMock.createInternalClient( Promise.resolve(clusterSettingsResponse) ); - const task = initAction({ ...initActionParams, client }); + const task = checkClusterRoutingAllocationEnabled(client); const result = await task(); expect(Either.isLeft(result)).toEqual(true); }); @@ -107,7 +101,7 @@ describe('initAction', () => { const client = elasticsearchClientMock.createInternalClient( Promise.resolve(clusterSettingsResponse) ); - const task = initAction({ ...initActionParams, client }); + const task = checkClusterRoutingAllocationEnabled(client); const result = await task(); expect(Either.isRight(result)).toEqual(true); }); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/check_cluster_routing_allocation.ts similarity index 57% rename from packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.ts rename to packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/check_cluster_routing_allocation.ts index 7db32f7a67d99c..a64c03d91e2193 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/initialize_action.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/check_cluster_routing_allocation.ts @@ -8,35 +8,22 @@ import * as TaskEither from 'fp-ts/lib/TaskEither'; import * as Either from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/function'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { catchRetryableEsClientErrors, type RetryableEsClientError, } from './catch_retryable_es_client_errors'; -import { type FetchIndexResponse, fetchIndices } from './fetch_indices'; - -const routingAllocationEnable = 'cluster.routing.allocation.enable'; -export interface ClusterRoutingAllocationEnabled { - clusterRoutingAllocationEnabled: boolean; -} - -export interface InitActionParams { - client: ElasticsearchClient; - indices: string[]; -} +const ROUTING_ALLOCATION_ENABLE = 'cluster.routing.allocation.enable'; export interface IncompatibleClusterRoutingAllocation { type: 'incompatible_cluster_routing_allocation'; } -export const checkClusterRoutingAllocationEnabledTask = - ({ - client, - }: { - client: ElasticsearchClient; - }): TaskEither.TaskEither => +export const checkClusterRoutingAllocationEnabled = + ( + client: ElasticsearchClient + ): TaskEither.TaskEither => () => { return client.cluster .getSettings({ @@ -45,8 +32,8 @@ export const checkClusterRoutingAllocationEnabledTask = .then((settings) => { // transient settings take preference over persistent settings const clusterRoutingAllocation = - settings?.transient?.[routingAllocationEnable] ?? - settings?.persistent?.[routingAllocationEnable]; + settings?.transient?.[ROUTING_ALLOCATION_ENABLE] ?? + settings?.persistent?.[ROUTING_ALLOCATION_ENABLE]; const clusterRoutingAllocationEnabledIsAll = clusterRoutingAllocation === undefined || clusterRoutingAllocation === 'all'; @@ -61,18 +48,3 @@ export const checkClusterRoutingAllocationEnabledTask = }) .catch(catchRetryableEsClientErrors); }; - -export const initAction = ({ - client, - indices, -}: InitActionParams): TaskEither.TaskEither< - RetryableEsClientError | IncompatibleClusterRoutingAllocation, - FetchIndexResponse -> => { - return pipe( - checkClusterRoutingAllocationEnabledTask({ client }), - TaskEither.chainW((value) => { - return fetchIndices({ client, indices }); - }) - ); -}; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts index 84f37c96cca5fa..35d05e13746673 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts @@ -21,8 +21,8 @@ export { export type { RetryableEsClientError }; // actions/* imports -export type { InitActionParams, IncompatibleClusterRoutingAllocation } from './initialize_action'; -export { initAction } from './initialize_action'; +export type { IncompatibleClusterRoutingAllocation } from './check_cluster_routing_allocation'; +export { checkClusterRoutingAllocationEnabled } from './check_cluster_routing_allocation'; export type { FetchIndexResponse, FetchIndicesParams } from './fetch_indices'; export { fetchIndices } from './fetch_indices'; @@ -108,7 +108,7 @@ export { } from './update_source_mappings_properties'; import type { UnknownDocsFound } from './check_for_unknown_docs'; -import type { IncompatibleClusterRoutingAllocation } from './initialize_action'; +import type { IncompatibleClusterRoutingAllocation } from './check_cluster_routing_allocation'; import type { ClusterShardLimitExceeded } from './create_index'; import type { SynchronizationFailed } from './synchronize_migrators'; import type { IndexMappingsIncomplete, TypesChanged } from './check_target_mappings'; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts index 1980a6e6128db4..961bc08e735ee5 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts @@ -39,7 +39,6 @@ import type { OutdatedDocumentsSearchOpenPit, OutdatedDocumentsSearchRead, OutdatedDocumentsTransform, - PostInitState, PrepareCompatibleMigration, RefreshTarget, ReindexSourceToTempClosePit, @@ -57,6 +56,8 @@ import type { WaitForYellowSourceState, ReadyToReindexSyncState, DoneReindexingSyncState, + LegacyCheckClusterRoutingAllocationState, + CheckClusterRoutingAllocationState, } from '../state'; import { type TransformErrorObjects, TransformSavedObjectDocumentError } from '../core'; import type { AliasAction, RetryableEsClientError } from '../actions'; @@ -175,6 +176,7 @@ describe('migrations v2 model', () => { type: 'retryable_es_client_error', message: 'snapshot_in_progress_exception', }; + test('increments retryCount, exponential retryDelay if an action fails with a retryable_es_client_error', () => { const states = new Array(10).fill(1).map(() => { state = model(state, Either.left(retryableError)); @@ -301,49 +303,59 @@ describe('migrations v2 model', () => { }, } as const; - describe('if waitForMigrationCompletion=true', () => { - const initState = Object.assign({}, initBaseState, { - waitForMigrationCompletion: true, + test("INIT -> FATAL when .kibana points to newer version's index", () => { + const res: ResponseType<'INIT'> = Either.right({ + '.kibana_7.12.0_001': { + aliases: { + '.kibana': {}, + '.kibana_7.12.0': {}, + }, + mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, + settings: {}, + }, + '.kibana_7.11.0_001': { + aliases: { '.kibana_7.11.0': {} }, + mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, + settings: {}, + }, }); - test('INIT -> INIT when cluster routing allocation is incompatible', () => { - const res: ResponseType<'INIT'> = Either.left({ - type: 'incompatible_cluster_routing_allocation', - }); - const newState = model(initState, res) as FatalState; + const newState = model(initBaseState, res) as FatalState; - expect(newState.controlState).toEqual('INIT'); - expect(newState.retryCount).toEqual(1); - expect(newState.retryDelay).toEqual(2000); - expect(newState.logs[0]).toMatchInlineSnapshot(` - Object { - "level": "error", - "message": "Action failed with '[incompatible_cluster_routing_allocation] Incompatible Elasticsearch cluster settings detected. Remove the persistent and transient Elasticsearch cluster setting 'cluster.routing.allocation.enable' or set it to a value of 'all' to allow migrations to proceed. Refer to routingAllocationDisabled for more information on how to resolve the issue.'. Retrying attempt 1 in 2 seconds.", - } - `); - }); - test("INIT -> FATAL when .kibana points to newer version's index", () => { - const res: ResponseType<'INIT'> = Either.right({ - '.kibana_7.12.0_001': { - aliases: { - '.kibana': {}, - '.kibana_7.12.0': {}, - }, - mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, - settings: {}, - }, - '.kibana_7.11.0_001': { - aliases: { '.kibana_7.11.0': {} }, - mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, - settings: {}, + expect(newState.controlState).toEqual('FATAL'); + expect(newState.reason).toMatchInlineSnapshot( + `"The .kibana alias is pointing to a newer version of Kibana: v7.12.0"` + ); + }); + + test('INIT -> FATAL when .kibana points to multiple indices', () => { + const res: ResponseType<'INIT'> = Either.right({ + '.kibana_7.12.0_001': { + aliases: { + '.kibana': {}, + '.kibana_7.12.0': {}, }, - }); - const newState = model(initState, res) as FatalState; + mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, + settings: {}, + }, + '.kibana_7.11.0_001': { + aliases: { '.kibana': {}, '.kibana_7.11.0': {} }, + mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, + settings: {}, + }, + }); + const newState = model(initBaseState, res) as FatalState; - expect(newState.controlState).toEqual('FATAL'); - expect(newState.reason).toMatchInlineSnapshot( - `"The .kibana alias is pointing to a newer version of Kibana: v7.12.0"` - ); + expect(newState.controlState).toEqual('FATAL'); + expect(newState.reason).toMatchInlineSnapshot( + `"The .kibana alias is pointing to multiple indices: .kibana_7.12.0_001,.kibana_7.11.0_001."` + ); + }); + + describe('if waitForMigrationCompletion=true', () => { + const initState = Object.assign({}, initBaseState, { + waitForMigrationCompletion: true, }); + test('INIT -> FATAL when later version alias exists', () => { const res: ResponseType<'INIT'> = Either.right({ '.kibana_7.11.0_001': { @@ -359,29 +371,7 @@ describe('migrations v2 model', () => { `"The .kibana_7.12.0 alias refers to a newer version of Kibana: v7.12.0"` ); }); - test('INIT -> FATAL when .kibana points to multiple indices', () => { - const res: ResponseType<'INIT'> = Either.right({ - '.kibana_7.12.0_001': { - aliases: { - '.kibana': {}, - '.kibana_7.12.0': {}, - }, - mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, - settings: {}, - }, - '.kibana_7.11.0_001': { - aliases: { '.kibana': {}, '.kibana_7.11.0': {} }, - mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, - settings: {}, - }, - }); - const newState = model(initState, res) as FatalState; - expect(newState.controlState).toEqual('FATAL'); - expect(newState.reason).toMatchInlineSnapshot( - `"The .kibana alias is pointing to multiple indices: .kibana_7.12.0_001,.kibana_7.11.0_001."` - ); - }); test('INIT -> WAIT_FOR_MIGRATION_COMPLETION when .kibana points to an index with an invalid version', () => { // If users tamper with our index version naming scheme we can no // longer accurately detect a newer version. Older Kibana versions @@ -405,11 +395,12 @@ describe('migrations v2 model', () => { settings: {}, }, }); - const newState = model(initState, res) as WaitForYellowSourceState; + const newState = model(initState, res); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toBe(2000); }); + test('INIT -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a v2 migrations index (>= 7.11.0)', () => { const res: ResponseType<'INIT'> = Either.right({ '.kibana_7.11.0_001': { @@ -431,11 +422,12 @@ describe('migrations v2 model', () => { versionIndex: '.kibana_7.12.0_001', }, res - ) as WaitForYellowSourceState; + ); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('INIT -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a v1 migrations index (>= 6.5 < 7.11.0)', () => { const res: ResponseType<'INIT'> = Either.right({ '.kibana_3': { @@ -446,11 +438,12 @@ describe('migrations v2 model', () => { settings: {}, }, }); - const newState = model(initState, res) as WaitForYellowSourceState; + const newState = model(initState, res); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('INIT -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a legacy index (>= 6.0.0 < 6.5)', () => { const res: ResponseType<'INIT'> = Either.right({ '.kibana': { @@ -464,6 +457,7 @@ describe('migrations v2 model', () => { expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('INIT -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a custom kibana.index name (>= 6.5 < 7.11.0)', () => { const res: ResponseType<'INIT'> = Either.right({ 'my-saved-objects_3': { @@ -483,11 +477,12 @@ describe('migrations v2 model', () => { versionIndex: 'my-saved-objects_7.11.0_001', }, res - ) as WaitForYellowSourceState; + ); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('INIT -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a custom kibana.index v2 migrations index (>= 7.11.0)', () => { const res: ResponseType<'INIT'> = Either.right({ 'my-saved-objects_7.11.0': { @@ -508,11 +503,12 @@ describe('migrations v2 model', () => { versionIndex: 'my-saved-objects_7.12.0_001', }, res - ) as WaitForYellowSourceState; + ); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('INIT -> WAIT_FOR_MIGRATION_COMPLETION when no indices/aliases exist', () => { const res: ResponseType<'INIT'> = Either.right({}); const newState = model(initState, res); @@ -526,68 +522,7 @@ describe('migrations v2 model', () => { const initState = Object.assign({}, initBaseState, { waitForMigrationCompletion: false, }); - test('INIT -> INIT when cluster routing allocation is incompatible', () => { - const res: ResponseType<'INIT'> = Either.left({ - type: 'incompatible_cluster_routing_allocation', - }); - const newState = model(initState, res) as FatalState; - expect(newState.controlState).toEqual('INIT'); - expect(newState.retryCount).toEqual(1); - expect(newState.retryDelay).toEqual(2000); - expect(newState.logs[0]).toMatchInlineSnapshot(` - Object { - "level": "error", - "message": "Action failed with '[incompatible_cluster_routing_allocation] Incompatible Elasticsearch cluster settings detected. Remove the persistent and transient Elasticsearch cluster setting 'cluster.routing.allocation.enable' or set it to a value of 'all' to allow migrations to proceed. Refer to routingAllocationDisabled for more information on how to resolve the issue.'. Retrying attempt 1 in 2 seconds.", - } - `); - }); - test("INIT -> FATAL when .kibana points to newer version's index", () => { - const res: ResponseType<'INIT'> = Either.right({ - '.kibana_7.12.0_001': { - aliases: { - '.kibana': {}, - '.kibana_7.12.0': {}, - }, - mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, - settings: {}, - }, - '.kibana_7.11.0_001': { - aliases: { '.kibana_7.11.0': {} }, - mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, - settings: {}, - }, - }); - const newState = model(initState, res) as FatalState; - - expect(newState.controlState).toEqual('FATAL'); - expect(newState.reason).toMatchInlineSnapshot( - `"The .kibana alias is pointing to a newer version of Kibana: v7.12.0"` - ); - }); - test('INIT -> FATAL when .kibana points to multiple indices', () => { - const res: ResponseType<'INIT'> = Either.right({ - '.kibana_7.12.0_001': { - aliases: { - '.kibana': {}, - '.kibana_7.12.0': {}, - }, - mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, - settings: {}, - }, - '.kibana_7.11.0_001': { - aliases: { '.kibana': {}, '.kibana_7.11.0': {} }, - mappings: { properties: {}, _meta: { migrationMappingPropertyHashes: {} } }, - settings: {}, - }, - }); - const newState = model(initState, res) as FatalState; - - expect(newState.controlState).toEqual('FATAL'); - expect(newState.reason).toMatchInlineSnapshot( - `"The .kibana alias is pointing to multiple indices: .kibana_7.12.0_001,.kibana_7.11.0_001."` - ); - }); test('INIT -> WAIT_FOR_YELLOW_SOURCE when .kibana points to an index with an invalid version', () => { // If users tamper with our index version naming scheme we can no // longer accurately detect a newer version. Older Kibana versions @@ -675,7 +610,8 @@ describe('migrations v2 model', () => { '.kibana': '.kibana_3', }); }); - test('INIT -> LEGACY_SET_WRITE_BLOCK when migrating from a legacy index (>= 6.0.0 < 6.5)', () => { + + test('INIT -> LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION when migrating from a legacy index (>= 6.0.0 < 6.5)', () => { const res: ResponseType<'INIT'> = Either.right({ '.kibana': { aliases: {}, @@ -686,7 +622,7 @@ describe('migrations v2 model', () => { const newState = model(initState, res); expect(newState).toMatchObject({ - controlState: 'LEGACY_SET_WRITE_BLOCK', + controlState: 'LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION', sourceIndex: Option.some('.kibana_pre6.5.0_001'), targetIndex: '.kibana_7.11.0_001', }); @@ -714,6 +650,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('INIT -> WAIT_FOR_YELLOW_SOURCE when migrating from a custom kibana.index name (>= 6.5 < 7.11.0)', () => { const res: ResponseType<'INIT'> = Either.right({ 'my-saved-objects_3': { @@ -740,6 +677,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('INIT -> WAIT_FOR_YELLOW_SOURCE when migrating from a custom kibana.index v2 migrations index (>= 7.11.0)', () => { const res: ResponseType<'INIT'> = Either.right({ 'my-saved-objects_7.11.0': { @@ -768,6 +706,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('INIT -> CREATE_NEW_TARGET when the index does not exist and the migrator is NOT involved in a relocation', () => { const res: ResponseType<'INIT'> = Either.right({}); const newState = model(initState, res); @@ -780,6 +719,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('INIT -> CREATE_REINDEX_TEMP when the index does not exist and the migrator is involved in a relocation', () => { const res: ResponseType<'INIT'> = Either.right({}); const newState = model( @@ -837,11 +777,12 @@ describe('migrations v2 model', () => { settings: {}, }, }); - const newState = model(waitForMState, res) as WaitForYellowSourceState; + const newState = model(waitForMState, res); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toBe(2000); }); + test('WAIT_FOR_MIGRATION_COMPLETION -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a v2 migrations index (>= 7.11.0)', () => { const res: ResponseType<'WAIT_FOR_MIGRATION_COMPLETION'> = Either.right({ '.kibana_7.11.0_001': { @@ -865,11 +806,12 @@ describe('migrations v2 model', () => { }, }, res - ) as WaitForYellowSourceState; + ); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('WAIT_FOR_MIGRATION_COMPLETION -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a v1 migrations index (>= 6.5 < 7.11.0)', () => { const res: ResponseType<'WAIT_FOR_MIGRATION_COMPLETION'> = Either.right({ '.kibana_3': { @@ -880,11 +822,12 @@ describe('migrations v2 model', () => { settings: {}, }, }); - const newState = model(waitForMState, res) as WaitForYellowSourceState; + const newState = model(waitForMState, res); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('WAIT_FOR_MIGRATION_COMPLETION -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a legacy index (>= 6.0.0 < 6.5)', () => { const res: ResponseType<'WAIT_FOR_MIGRATION_COMPLETION'> = Either.right({ '.kibana': { @@ -898,6 +841,7 @@ describe('migrations v2 model', () => { expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('WAIT_FOR_MIGRATION_COMPLETION -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a custom kibana.index name (>= 6.5 < 7.11.0)', () => { const res: ResponseType<'WAIT_FOR_MIGRATION_COMPLETION'> = Either.right({ 'my-saved-objects_3': { @@ -916,11 +860,12 @@ describe('migrations v2 model', () => { versionIndex: 'my-saved-objects_7.11.0_001', }, res - ) as WaitForYellowSourceState; + ); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('WAIT_FOR_MIGRATION_COMPLETION -> WAIT_FOR_MIGRATION_COMPLETION when migrating from a custom kibana.index v2 migrations index (>= 7.11.0)', () => { const res: ResponseType<'WAIT_FOR_MIGRATION_COMPLETION'> = Either.right({ 'my-saved-objects_7.11.0': { @@ -940,11 +885,12 @@ describe('migrations v2 model', () => { versionIndex: 'my-saved-objects_7.12.0_001', }, res - ) as WaitForYellowSourceState; + ); expect(newState.controlState).toBe('WAIT_FOR_MIGRATION_COMPLETION'); expect(newState.retryDelay).toEqual(2000); }); + test('WAIT_FOR_MIGRATION_COMPLETION -> WAIT_FOR_MIGRATION_COMPLETION when no indices/aliases exist', () => { const res: ResponseType<'WAIT_FOR_MIGRATION_COMPLETION'> = Either.right({}); const newState = model(waitForMState, res); @@ -970,6 +916,37 @@ describe('migrations v2 model', () => { }); }); + describe('LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION', () => { + const legacyCheckClusterRoutingAllocationState: LegacyCheckClusterRoutingAllocationState = { + ...postInitState, + controlState: 'LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION', + sourceIndex: Option.some('.kibana') as Option.Some, + sourceIndexMappings: Option.some({ properties: {} }) as Option.Some, + legacyPreMigrationDoneActions: [], + legacyIndex: '', + }; + + test('LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION -> LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION when cluster allocation is not compatible', () => { + const res: ResponseType<'LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION'> = Either.left({ + type: 'incompatible_cluster_routing_allocation', + }); + const newState = model(legacyCheckClusterRoutingAllocationState, res); + + expect(newState.controlState).toBe('LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION'); + expect(newState.retryCount).toEqual(1); + expect(newState.retryDelay).toEqual(2000); + }); + + test('LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION -> LEGACY_SET_WRITE_BLOCK when cluster allocation is compatible', () => { + const res: ResponseType<'LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION'> = Either.right({}); + const newState = model(legacyCheckClusterRoutingAllocationState, res); + + expect(newState.controlState).toBe('LEGACY_SET_WRITE_BLOCK'); + expect(newState.retryCount).toEqual(0); + expect(newState.retryDelay).toEqual(0); + }); + }); + describe('LEGACY_SET_WRITE_BLOCK', () => { const legacySetWriteBlockState: LegacySetWriteBlockState = { ...postInitState, @@ -979,6 +956,7 @@ describe('migrations v2 model', () => { legacyPreMigrationDoneActions: [], legacyIndex: '', }; + test('LEGACY_SET_WRITE_BLOCK -> LEGACY_SET_WRITE_BLOCK if action fails with set_write_block_failed', () => { const res: ResponseType<'LEGACY_SET_WRITE_BLOCK'> = Either.left({ type: 'retryable_es_client_error', @@ -989,6 +967,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(1); expect(newState.retryDelay).toEqual(2000); }); + test('LEGACY_SET_WRITE_BLOCK -> LEGACY_CREATE_REINDEX_TARGET if action fails with index_not_found_exception', () => { const res: ResponseType<'LEGACY_SET_WRITE_BLOCK'> = Either.left({ type: 'index_not_found_exception', @@ -999,6 +978,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('LEGACY_SET_WRITE_BLOCK -> LEGACY_CREATE_REINDEX_TARGET if action succeeds with set_write_block_succeeded', () => { const res: ResponseType<'LEGACY_SET_WRITE_BLOCK'> = Either.right( 'set_write_block_succeeded' @@ -1019,6 +999,7 @@ describe('migrations v2 model', () => { legacyPreMigrationDoneActions: [], legacyIndex: '', }; + test('LEGACY_CREATE_REINDEX_TARGET -> LEGACY_REINDEX', () => { const res: ResponseType<'LEGACY_CREATE_REINDEX_TARGET'> = Either.right('create_index_succeeded'); @@ -1027,6 +1008,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('LEGACY_CREATE_REINDEX_TARGET -> LEGACY_CREATE_REINDEX_TARGET if action fails with index_not_green_timeout', () => { const res: ResponseType<'LEGACY_CREATE_REINDEX_TARGET'> = Either.left({ message: '[index_not_green_timeout] Timeout waiting for ...', @@ -1043,6 +1025,7 @@ describe('migrations v2 model', () => { } `); }); + test('LEGACY_CREATE_REINDEX_TARGET -> LEGACY_REINDEX resets retry count and retry delay if action succeeds', () => { const res: ResponseType<'LEGACY_CREATE_REINDEX_TARGET'> = Either.right('create_index_succeeded'); @@ -1056,13 +1039,14 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('LEGACY_CREATE_REINDEX_TARGET -> FATAL if action fails with cluster_shard_limit_exceeded', () => { const res: ResponseType<'LEGACY_CREATE_REINDEX_TARGET'> = Either.left({ type: 'cluster_shard_limit_exceeded', }); - const newState = model(legacyCreateReindexTargetState, res); + const newState = model(legacyCreateReindexTargetState, res) as FatalState; expect(newState.controlState).toEqual('FATAL'); - expect((newState as FatalState).reason).toMatchInlineSnapshot( + expect(newState.reason).toMatchInlineSnapshot( `"[cluster_shard_limit_exceeded] Upgrading Kibana requires adding a small number of new shards. Ensure that Kibana is able to add 10 more shards by increasing the cluster.max_shards_per_node setting, or removing indices to clear up resources. See clusterShardLimitExceeded"` ); }); @@ -1077,6 +1061,7 @@ describe('migrations v2 model', () => { legacyPreMigrationDoneActions: [], legacyIndex: '', }; + test('LEGACY_REINDEX -> LEGACY_REINDEX_WAIT_FOR_TASK', () => { const res: ResponseType<'LEGACY_REINDEX'> = Either.right({ taskId: 'task id' }); const newState = model(legacyReindexState, res); @@ -1096,6 +1081,7 @@ describe('migrations v2 model', () => { legacyIndex: 'legacy_index_name', legacyReindexTaskId: 'test_task_id', }; + test('LEGACY_REINDEX_WAIT_FOR_TASK -> LEGACY_DELETE if action succeeds', () => { const res: ResponseType<'LEGACY_REINDEX_WAIT_FOR_TASK'> = Either.right('reindex_succeeded'); const newState = model(legacyReindexWaitForTaskState, res); @@ -1103,6 +1089,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('LEGACY_REINDEX_WAIT_FOR_TASK -> LEGACY_DELETE if action fails with index_not_found_exception for reindex source', () => { const res: ResponseType<'LEGACY_REINDEX_WAIT_FOR_TASK'> = Either.left({ type: 'index_not_found_exception', @@ -1113,6 +1100,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('LEGACY_REINDEX_WAIT_FOR_TASK -> LEGACY_DELETE if action fails with target_index_had_write_block', () => { const res: ResponseType<'LEGACY_REINDEX_WAIT_FOR_TASK'> = Either.left({ type: 'target_index_had_write_block', @@ -1122,6 +1110,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('LEGACY_REINDEX_WAIT_FOR_TASK -> LEGACY_REINDEX_WAIT_FOR_TASK if action fails with wait_for_task_completion_timeout', () => { const res: ResponseType<'LEGACY_REINDEX_WAIT_FOR_TASK'> = Either.left({ message: '[timeout_exception] Timeout waiting for ...', @@ -1132,6 +1121,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(1); expect(newState.retryDelay).toEqual(2000); }); + test('LEGACY_REINDEX_WAIT_FOR_TASK -> LEGACY_REINDEX_WAIT_FOR_TASK with incremented retryCount if action fails with wait_for_task_completion_timeout a second time', () => { const state = Object.assign({}, legacyReindexWaitForTaskState, { retryCount: 1 }); const res: ResponseType<'LEGACY_REINDEX_WAIT_FOR_TASK'> = Either.left({ @@ -1154,6 +1144,7 @@ describe('migrations v2 model', () => { legacyPreMigrationDoneActions: [], legacyIndex: 'legacy_index_name', }; + test('LEGACY_DELETE -> SET_SOURCE_WRITE_BLOCK if action succeeds', () => { const res: ResponseType<'LEGACY_DELETE'> = Either.right('update_aliases_succeeded'); const newState = model(legacyDeleteState, res); @@ -1161,6 +1152,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('LEGACY_DELETE -> SET_SOURCE_WRITE_BLOCK if action fails with index_not_found_exception for legacy index', () => { const res: ResponseType<'LEGACY_REINDEX_WAIT_FOR_TASK'> = Either.left({ type: 'index_not_found_exception', @@ -1171,6 +1163,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('LEGACY_DELETE -> SET_SOURCE_WRITE_BLOCK if action fails with remove_index_not_a_concrete_index', () => { const res: ResponseType<'LEGACY_DELETE'> = Either.left({ type: 'remove_index_not_a_concrete_index', @@ -1209,25 +1202,20 @@ describe('migrations v2 model', () => { test('WAIT_FOR_YELLOW_SOURCE -> UPDATE_SOURCE_MAPPINGS_PROPERTIES', () => { const res: ResponseType<'WAIT_FOR_YELLOW_SOURCE'> = Either.right({}); const newState = model(waitForYellowSourceState, res); - - expect(newState).toMatchObject({ - controlState: 'UPDATE_SOURCE_MAPPINGS_PROPERTIES', - }); + expect(newState.controlState).toEqual('UPDATE_SOURCE_MAPPINGS_PROPERTIES'); }); }); describe('if the migrator is involved in a relocation', () => { // no need to attempt to update the mappings, we are going to reindex - test('WAIT_FOR_YELLOW_SOURCE -> CHECK_UNKNOWN_DOCUMENTS', () => { + test('WAIT_FOR_YELLOW_SOURCE -> CHECK_CLUSTER_ROUTING_ALLOCATION', () => { const res: ResponseType<'WAIT_FOR_YELLOW_SOURCE'> = Either.right({}); const newState = model( { ...waitForYellowSourceState, mustRelocateDocuments: true }, res ); - expect(newState).toMatchObject({ - controlState: 'CHECK_UNKNOWN_DOCUMENTS', - }); + expect(newState.controlState).toEqual('CHECK_CLUSTER_ROUTING_ALLOCATION'); }); }); }); @@ -1272,10 +1260,7 @@ describe('migrations v2 model', () => { 'update_mappings_succeeded' ); const newState = model(updateSourceMappingsPropertiesState, res); - - expect(newState).toMatchObject({ - controlState: 'CLEANUP_UNKNOWN_AND_EXCLUDED', - }); + expect(newState.controlState).toEqual('CLEANUP_UNKNOWN_AND_EXCLUDED'); }); test('UPDATE_SOURCE_MAPPINGS_PROPERTIES -> OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT if mappings changes are compatible and index is already migrated', () => { @@ -1305,15 +1290,12 @@ describe('migrations v2 model', () => { }); describe('if action fails', () => { - test('UPDATE_SOURCE_MAPPINGS_PROPERTIES -> CHECK_UNKNOWN_DOCUMENTS if mappings changes are incompatible', () => { + test('UPDATE_SOURCE_MAPPINGS_PROPERTIES -> CHECK_CLUSTER_ROUTING_ALLOCATION if mappings changes are incompatible', () => { const res: ResponseType<'UPDATE_SOURCE_MAPPINGS_PROPERTIES'> = Either.left({ type: 'incompatible_mapping_exception', }); const newState = model(updateSourceMappingsPropertiesState, res); - - expect(newState).toMatchObject({ - controlState: 'CHECK_UNKNOWN_DOCUMENTS', - }); + expect(newState.controlState).toEqual('CHECK_CLUSTER_ROUTING_ALLOCATION'); }); test('UPDATE_SOURCE_MAPPINGS_PROPERTIES -> FATAL', () => { @@ -1326,11 +1308,12 @@ describe('migrations v2 model', () => { .set(['aliases', '.kibana'], '.kibana_7.11.0_001') .value(), res - ); + ) as FatalState; - expect(newState).toMatchObject({ - controlState: 'FATAL', - }); + expect(newState.controlState).toEqual('FATAL'); + expect(newState.reason).toMatchInlineSnapshot( + `"Incompatible mappings change on already migrated Kibana instance."` + ); }); }); }); @@ -1485,6 +1468,35 @@ describe('migrations v2 model', () => { }); }); + describe('CHECK_CLUSTER_ROUTING_ALLOCATION', () => { + const checkClusterRoutingAllocationState: CheckClusterRoutingAllocationState = { + ...postInitState, + controlState: 'CHECK_CLUSTER_ROUTING_ALLOCATION', + sourceIndex: Option.some('.kibana') as Option.Some, + sourceIndexMappings: Option.some({}) as Option.Some, + }; + + test('CHECK_CLUSTER_ROUTING_ALLOCATION -> CHECK_CLUSTER_ROUTING_ALLOCATION when cluster allocation is not compatible', () => { + const res: ResponseType<'CHECK_CLUSTER_ROUTING_ALLOCATION'> = Either.left({ + type: 'incompatible_cluster_routing_allocation', + }); + const newState = model(checkClusterRoutingAllocationState, res); + + expect(newState.controlState).toBe('CHECK_CLUSTER_ROUTING_ALLOCATION'); + expect(newState.retryCount).toEqual(1); + expect(newState.retryDelay).toEqual(2000); + }); + + test('CHECK_CLUSTER_ROUTING_ALLOCATION -> CHECK_UNKNOWN_DOCUMENTS when cluster allocation is compatible', () => { + const res: ResponseType<'CHECK_CLUSTER_ROUTING_ALLOCATION'> = Either.right({}); + const newState = model(checkClusterRoutingAllocationState, res); + + expect(newState.controlState).toBe('CHECK_UNKNOWN_DOCUMENTS'); + expect(newState.retryCount).toEqual(0); + expect(newState.retryDelay).toEqual(0); + }); + }); + describe('CHECK_UNKNOWN_DOCUMENTS', () => { const mappingsWithUnknownType = { properties: { @@ -1626,6 +1638,7 @@ describe('migrations v2 model', () => { sourceIndex: Option.some('.kibana') as Option.Some, sourceIndexMappings: Option.some({}) as Option.Some, }; + test('SET_SOURCE_WRITE_BLOCK -> SET_SOURCE_WRITE_BLOCK if action fails with set_write_block_failed', () => { const res: ResponseType<'SET_SOURCE_WRITE_BLOCK'> = Either.left({ type: 'retryable_es_client_error', @@ -1636,6 +1649,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(1); expect(newState.retryDelay).toEqual(2000); }); + test('SET_SOURCE_WRITE_BLOCK -> CALCULATE_EXCLUDE_FILTERS if action succeeds with set_write_block_succeeded', () => { const res: ResponseType<'SET_SOURCE_WRITE_BLOCK'> = Either.right( 'set_write_block_succeeded' @@ -1664,6 +1678,7 @@ describe('migrations v2 model', () => { sourceIndexMappings: Option.some({}) as Option.Some, tempIndexMappings: { properties: {} }, }; + test('CALCULATE_EXCLUDE_FILTERS -> CALCULATE_EXCLUDE_FILTERS if action fails with retryable error', () => { const res: ResponseType<'CALCULATE_EXCLUDE_FILTERS'> = Either.left({ type: 'retryable_es_client_error', @@ -1764,13 +1779,14 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('CREATE_REINDEX_TEMP -> FATAL if action fails with cluster_shard_limit_exceeded', () => { const res: ResponseType<'CREATE_REINDEX_TEMP'> = Either.left({ type: 'cluster_shard_limit_exceeded', }); - const newState = model(state, res); + const newState = model(state, res) as FatalState; expect(newState.controlState).toEqual('FATAL'); - expect((newState as FatalState).reason).toMatchInlineSnapshot( + expect(newState.reason).toMatchInlineSnapshot( `"[cluster_shard_limit_exceeded] Upgrading Kibana requires adding a small number of new shards. Ensure that Kibana is able to add 10 more shards by increasing the cluster.max_shards_per_node setting, or removing indices to clear up resources. See clusterShardLimitExceeded"` ); }); @@ -1816,9 +1832,9 @@ describe('migrations v2 model', () => { type: 'synchronization_failed', error: new Error('Other migrators failed to reach the synchronization point'), }); - const newState = model(state, res); + const newState = model(state, res) as FatalState; expect(newState.controlState).toEqual('FATAL'); - expect((newState as FatalState).reason).toMatchInlineSnapshot( + expect(newState.reason).toMatchInlineSnapshot( `"An error occurred whilst waiting for other migrators to get to this step."` ); }); @@ -1955,12 +1971,13 @@ describe('migrations v2 model', () => { contentLength: 2345, }); const newState = model({ ...state, batchSize: 1 }, res) as FatalState; - expect(newState.controlState).toBe('FATAL'); - expect(newState.batchSize).toBe(1); // don't halve the batch size or go below 1 - expect(newState.maxBatchSize).toBe(1000); // leaves maxBatchSize unchanged - expect(newState.reason).toMatchInlineSnapshot( - `"After reducing the read batch size to a single document, the Elasticsearch response content length was 2345bytes which still exceeded migrations.maxReadBatchSizeBytes. Increase migrations.maxReadBatchSizeBytes and try again."` - ); + expect(newState).toMatchObject({ + controlState: 'FATAL', + batchSize: 1, + maxBatchSize: 1000, + reason: + 'After reducing the read batch size to a single document, the Elasticsearch response content length was 2345bytes which still exceeded migrations.maxReadBatchSizeBytes. Increase migrations.maxReadBatchSizeBytes and try again.', + }); }); it('REINDEX_SOURCE_TO_TEMP_READ -> REINDEX_SOURCE_TO_TEMP_CLOSE_PIT if no outdated documents to reindex', () => { @@ -2073,14 +2090,15 @@ describe('migrations v2 model', () => { const newState = model(state, res); expect(newState.controlState).toEqual('SET_TEMP_WRITE_BLOCK'); }); + test('DONE_REINDEXING_SYNC -> FATAL if the synchronization between migrators fails', () => { const res: ResponseType<'DONE_REINDEXING_SYNC'> = Either.left({ type: 'synchronization_failed', error: new Error('Other migrators failed to reach the synchronization point'), }); - const newState = model(state, res); + const newState = model(state, res) as FatalState; expect(newState.controlState).toEqual('FATAL'); - expect((newState as FatalState).reason).toMatchInlineSnapshot( + expect(newState.reason).toMatchInlineSnapshot( `"An error occurred whilst waiting for other migrators to get to this step."` ); }); @@ -2177,6 +2195,7 @@ describe('migrations v2 model', () => { corruptDocumentIds: [], progress: createInitialProgress(), }; + test('REINDEX_SOURCE_TO_TEMP_INDEX_BULK -> REINDEX_SOURCE_TO_TEMP_READ if action succeeded', () => { const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX_BULK'> = Either.right('bulk_index_succeeded'); @@ -2185,6 +2204,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('REINDEX_SOURCE_TO_TEMP_INDEX_BULK -> REINDEX_SOURCE_TO_TEMP_CLOSE_PIT if response is left target_index_had_write_block', () => { const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX_BULK'> = Either.left({ type: 'target_index_had_write_block', @@ -2194,6 +2214,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('REINDEX_SOURCE_TO_TEMP_INDEX_BULK -> REINDEX_SOURCE_TO_TEMP_CLOSE_PIT if response is left index_not_found_exception', () => { const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX_BULK'> = Either.left({ type: 'index_not_found_exception', @@ -2204,6 +2225,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('REINDEX_SOURCE_TO_TEMP_INDEX_BULK -> FATAL if action returns left request_entity_too_large_exception', () => { const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX_BULK'> = Either.left({ type: 'request_entity_too_large_exception', @@ -2214,6 +2236,7 @@ describe('migrations v2 model', () => { `"While indexing a batch of saved objects, Elasticsearch returned a 413 Request Entity Too Large exception. Ensure that the Kibana configuration option 'migrations.maxBatchSizeBytes' is set to a value that is lower than or equal to the Elasticsearch 'http.max_content_length' configuration option."` ); }); + test('REINDEX_SOURCE_TO_TEMP_INDEX_BULK should throw a throwBadResponse error if action failed', () => { const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_INDEX_BULK'> = Either.left({ type: 'retryable_es_client_error', @@ -2233,6 +2256,7 @@ describe('migrations v2 model', () => { sourceIndex: Option.some('.kibana') as Option.Some, sourceIndexMappings: Option.some({}) as Option.Some, }; + test('SET_TEMP_WRITE_BLOCK -> CLONE_TEMP_TO_TARGET when response is right', () => { const res: ResponseType<'SET_TEMP_WRITE_BLOCK'> = Either.right('set_write_block_succeeded'); const newState = model(state, res); @@ -2299,13 +2323,14 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toBe(0); expect(newState.retryDelay).toBe(0); }); + test('CLONE_TEMP_TO_TARGET -> FATAL if action fails with cluster_shard_limit_exceeded', () => { const res: ResponseType<'CLONE_TEMP_TO_TARGET'> = Either.left({ type: 'cluster_shard_limit_exceeded', }); - const newState = model(state, res); + const newState = model(state, res) as FatalState; expect(newState.controlState).toEqual('FATAL'); - expect((newState as FatalState).reason).toMatchInlineSnapshot( + expect(newState.reason).toMatchInlineSnapshot( `"[cluster_shard_limit_exceeded] Upgrading Kibana requires adding a small number of new shards. Ensure that Kibana is able to add 10 more shards by increasing the cluster.max_shards_per_node setting, or removing indices to clear up resources. See clusterShardLimitExceeded"` ); }); @@ -2687,7 +2712,7 @@ describe('migrations v2 model', () => { it('REFRESH_TARGET -> OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT if action succeeded', () => { const res: ResponseType<'REFRESH_TARGET'> = Either.right({ refreshed: true }); - const newState = model(state, res) as UpdateTargetMappingsPropertiesState; + const newState = model(state, res); expect(newState.controlState).toBe('OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT'); }); }); @@ -2716,6 +2741,7 @@ describe('migrations v2 model', () => { hasTransformedDocs: false, progress: createInitialProgress(), }; + describe('OUTDATED_DOCUMENTS_TRANSFORM if action succeeds', () => { test('OUTDATED_DOCUMENTS_TRANSFORM -> TRANSFORMED_DOCUMENTS_BULK_INDEX if action succeeds', () => { const res: ResponseType<'OUTDATED_DOCUMENTS_TRANSFORM'> = Either.right({ processedDocs }); @@ -2730,6 +2756,7 @@ describe('migrations v2 model', () => { expect(newState.retryDelay).toEqual(0); expect(newState.progress.processed).toBe(outdatedDocuments.length); }); + test('OUTDATED_DOCUMENTS_TRANSFORM -> OUTDATED_DOCUMENTS_SEARCH_READ if there are are existing documents that failed transformation', () => { const outdatedDocumentsTransformStateWithFailedDocuments: OutdatedDocumentsTransform = { ...outdatedDocumentsTransformState, @@ -2747,6 +2774,7 @@ describe('migrations v2 model', () => { expect(newState.retryDelay).toEqual(0); expect(newState.progress.processed).toBe(outdatedDocuments.length); }); + test('OUTDATED_DOCUMENTS_TRANSFORM -> OUTDATED_DOCUMENTS_SEARCH_READ if there are are existing documents that failed transformation because of transform errors', () => { const outdatedDocumentsTransformStateWithFailedDocuments: OutdatedDocumentsTransform = { ...outdatedDocumentsTransformState, @@ -2766,6 +2794,7 @@ describe('migrations v2 model', () => { expect(newState.progress.processed).toBe(outdatedDocuments.length); }); }); + describe('OUTDATED_DOCUMENTS_TRANSFORM if action fails', () => { test('OUTDATED_DOCUMENTS_TRANSFORM -> OUTDATED_DOCUMENTS_SEARCH_READ adding newly failed documents to state if documents failed the transform', () => { const res: ResponseType<'OUTDATED_DOCUMENTS_TRANSFORM'> = Either.left({ @@ -2782,6 +2811,7 @@ describe('migrations v2 model', () => { expect(newState.corruptDocumentIds).toEqual(corruptDocumentIds); expect(newState.progress.processed).toBe(outdatedDocuments.length); }); + test('OUTDATED_DOCUMENTS_TRANSFORM -> OUTDATED_DOCUMENTS_SEARCH_READ combines newly failed documents with those already on state if documents failed the transform', () => { const newFailedTransformDocumentIds = ['b:other', 'c:__']; const outdatedDocumentsTransformStateWithFailedDocuments: OutdatedDocumentsTransform = { @@ -2917,6 +2947,7 @@ describe('migrations v2 model', () => { }, }), }; + test('UPDATE_TARGET_MAPPINGS_PROPERTIES -> UPDATE_TARGET_MAPPINGS_PROPERTIES_WAIT_FOR_TASK', () => { const res: ResponseType<'UPDATE_TARGET_MAPPINGS_PROPERTIES'> = Either.right({ taskId: 'update target mappings task', @@ -2961,10 +2992,7 @@ describe('migrations v2 model', () => { message: '[timeout_exception] Timeout waiting for ...', type: 'wait_for_task_completion_timeout', }); - const newState = model( - updateTargetMappingsWaitForTaskState, - res - ) as UpdateTargetMappingsPropertiesWaitForTaskState; + const newState = model(updateTargetMappingsWaitForTaskState, res); expect(newState.controlState).toEqual('UPDATE_TARGET_MAPPINGS_PROPERTIES_WAIT_FOR_TASK'); expect(newState.retryCount).toEqual(1); expect(newState.retryDelay).toEqual(2000); @@ -2976,7 +3004,7 @@ describe('migrations v2 model', () => { message: '[timeout_exception] Timeout waiting for ...', type: 'wait_for_task_completion_timeout', }); - const newState = model(state, res) as UpdateTargetMappingsPropertiesWaitForTaskState; + const newState = model(state, res); expect(newState.controlState).toEqual('UPDATE_TARGET_MAPPINGS_PROPERTIES_WAIT_FOR_TASK'); expect(newState.retryCount).toEqual(2); expect(newState.retryDelay).toEqual(4000); @@ -3023,7 +3051,7 @@ describe('migrations v2 model', () => { versionIndexReadyActions, }, res - ) as PostInitState; + ); expect(newState.controlState).toEqual('MARK_VERSION_INDEX_READY'); expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); @@ -3041,14 +3069,14 @@ describe('migrations v2 model', () => { versionIndexReadyActions, }, res - ) as PostInitState; + ); expect(newState.controlState).toEqual('MARK_VERSION_INDEX_READY_SYNC'); expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); test('CHECK_VERSION_INDEX_READY_ACTIONS -> DONE if none versionIndexReadyActions', () => { - const newState = model(сheckVersionIndexReadyActionsState, res) as PostInitState; + const newState = model(сheckVersionIndexReadyActionsState, res); expect(newState.controlState).toEqual('DONE'); expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); @@ -3066,6 +3094,7 @@ describe('migrations v2 model', () => { sourceIndex: Option.none as Option.None, targetIndex: '.kibana_7.11.0_001', }; + test('CREATE_NEW_TARGET -> CHECK_VERSION_INDEX_READY_ACTIONS', () => { const res: ResponseType<'CREATE_NEW_TARGET'> = Either.right('create_index_succeeded'); const newState = model(createNewTargetState, res); @@ -3073,6 +3102,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('CREATE_NEW_TARGET -> CREATE_NEW_TARGET if action fails with index_not_green_timeout', () => { const res: ResponseType<'CREATE_NEW_TARGET'> = Either.left({ message: '[index_not_green_timeout] Timeout waiting for ...', @@ -3083,6 +3113,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(1); expect(newState.retryDelay).toEqual(2000); }); + test('CREATE_NEW_TARGET -> CHECK_VERSION_INDEX_READY_ACTIONS resets the retry count and delay', () => { const res: ResponseType<'CREATE_NEW_TARGET'> = Either.right('create_index_succeeded'); const testState = { @@ -3096,13 +3127,14 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('CREATE_NEW_TARGET -> FATAL if action fails with cluster_shard_limit_exceeded', () => { const res: ResponseType<'CREATE_NEW_TARGET'> = Either.left({ type: 'cluster_shard_limit_exceeded', }); - const newState = model(createNewTargetState, res); + const newState = model(createNewTargetState, res) as FatalState; expect(newState.controlState).toEqual('FATAL'); - expect((newState as FatalState).reason).toMatchInlineSnapshot( + expect(newState.reason).toMatchInlineSnapshot( `"[cluster_shard_limit_exceeded] Upgrading Kibana requires adding a small number of new shards. Ensure that Kibana is able to add 10 more shards by increasing the cluster.max_shards_per_node setting, or removing indices to clear up resources. See clusterShardLimitExceeded"` ); }); @@ -3118,6 +3150,7 @@ describe('migrations v2 model', () => { versionIndexReadyActions: aliasActions, targetIndex: '.kibana_7.11.0_001', }; + test('MARK_VERSION_INDEX_READY -> DONE if the action succeeded', () => { const res: ResponseType<'MARK_VERSION_INDEX_READY'> = Either.right( 'update_aliases_succeeded' @@ -3127,6 +3160,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('MARK_VERSION_INDEX_READY -> MARK_VERSION_INDEX_CONFLICT if another removed the current alias from the source index', () => { const res: ResponseType<'MARK_VERSION_INDEX_READY'> = Either.left({ type: 'alias_not_found_exception', @@ -3136,6 +3170,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('MARK_VERSION_INDEX_READY -> MARK_VERSION_INDEX_CONFLICT if another node removed the temporary index', () => { const res: ResponseType<'MARK_VERSION_INDEX_READY'> = Either.left({ type: 'index_not_found_exception', @@ -3158,6 +3193,7 @@ describe('migrations v2 model', () => { versionIndexReadyActions: aliasActions, targetIndex: '.kibana_7.11.0_001', }; + test('MARK_VERSION_INDEX_CONFLICT -> DONE if the current alias is pointing to the version alias', () => { const res: ResponseType<'MARK_VERSION_INDEX_READY_CONFLICT'> = Either.right({ '.kibana_7.11.0_001': { @@ -3179,6 +3215,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('MARK_VERSION_INDEX_READY_CONFLICT -> FATAL if the current alias is pointing to a different version index', () => { const res: ResponseType<'MARK_VERSION_INDEX_READY_CONFLICT'> = Either.right({ '.kibana_7.11.0_001': { @@ -3203,6 +3240,7 @@ describe('migrations v2 model', () => { expect(newState.retryCount).toEqual(0); expect(newState.retryDelay).toEqual(0); }); + test('MARK_VERSION_INDEX_READY_CONFLICT -> FATAL if the current alias is pointing to a multiple indices', () => { const res: ResponseType<'MARK_VERSION_INDEX_READY_CONFLICT'> = Either.right({ '.kibana_7.11.0_001': { diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts index 4f1f48444dc230..cf0fe5fa3396b7 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts @@ -82,193 +82,181 @@ export const model = (currentState: State, resW: ResponseType): if (stateP.controlState === 'INIT') { const res = resW as ExcludeRetryableEsError>; - if (Either.isLeft(res)) { - const left = res.left; - if (isTypeof(left, 'incompatible_cluster_routing_allocation')) { - const retryErrorMessage = `[${left.type}] Incompatible Elasticsearch cluster settings detected. Remove the persistent and transient Elasticsearch cluster setting 'cluster.routing.allocation.enable' or set it to a value of 'all' to allow migrations to proceed. Refer to ${stateP.migrationDocLinks.routingAllocationDisabled} for more information on how to resolve the issue.`; - return delayRetryState(stateP, retryErrorMessage, stateP.retryAttempts); - } else { - throwBadResponse(stateP, left); - } - } else if (Either.isRight(res)) { - // cluster routing allocation is enabled and we can continue with the migration as normal - const indices = res.right; - const aliasesRes = getAliases(indices); + // cluster routing allocation is enabled and we can continue with the migration as normal + const indices = res.right; + const aliasesRes = getAliases(indices); - if (Either.isLeft(aliasesRes)) { - return { - ...stateP, - controlState: 'FATAL', - reason: `The ${ - aliasesRes.left.alias - } alias is pointing to multiple indices: ${aliasesRes.left.indices.join(',')}.`, - }; - } + if (Either.isLeft(aliasesRes)) { + return { + ...stateP, + controlState: 'FATAL', + reason: `The ${ + aliasesRes.left.alias + } alias is pointing to multiple indices: ${aliasesRes.left.indices.join(',')}.`, + }; + } - const aliases = aliasesRes.right; + const aliases = aliasesRes.right; - if ( - // `.kibana` is pointing to an index that belongs to a later - // version of Kibana .e.g. a 7.11.0 instance found the `.kibana` alias - // pointing to `.kibana_7.12.0_001` - indexBelongsToLaterVersion(stateP.kibanaVersion, aliases[stateP.currentAlias]) - ) { - return { - ...stateP, - controlState: 'FATAL', - reason: `The ${ - stateP.currentAlias - } alias is pointing to a newer version of Kibana: v${indexVersion( - aliases[stateP.currentAlias] - )}`, - }; - } + if ( + // `.kibana` is pointing to an index that belongs to a later + // version of Kibana .e.g. a 7.11.0 instance found the `.kibana` alias + // pointing to `.kibana_7.12.0_001` + indexBelongsToLaterVersion(stateP.kibanaVersion, aliases[stateP.currentAlias]) + ) { + return { + ...stateP, + controlState: 'FATAL', + reason: `The ${ + stateP.currentAlias + } alias is pointing to a newer version of Kibana: v${indexVersion( + aliases[stateP.currentAlias] + )}`, + }; + } - const laterVersionAlias = hasLaterVersionAlias(stateP.kibanaVersion, aliases); - if ( - // a `.kibana_` alias exist, which refers to a later version of Kibana - // e.g. `.kibana_8.7.0` exists, and current stack version is 8.6.1 - // see https://github.com/elastic/kibana/issues/155136 - laterVersionAlias - ) { - return { - ...stateP, - controlState: 'FATAL', - reason: `The ${laterVersionAlias} alias refers to a newer version of Kibana: v${aliasVersion( - laterVersionAlias - )}`, - }; - } + const laterVersionAlias = hasLaterVersionAlias(stateP.kibanaVersion, aliases); + if ( + // a `.kibana_` alias exist, which refers to a later version of Kibana + // e.g. `.kibana_8.7.0` exists, and current stack version is 8.6.1 + // see https://github.com/elastic/kibana/issues/155136 + laterVersionAlias + ) { + return { + ...stateP, + controlState: 'FATAL', + reason: `The ${laterVersionAlias} alias refers to a newer version of Kibana: v${aliasVersion( + laterVersionAlias + )}`, + }; + } - // The source index .kibana is pointing to. E.g: ".kibana_8.7.0_001" - const source = aliases[stateP.currentAlias]; - // The target index .kibana WILL be pointing to if we reindex. E.g: ".kibana_8.8.0_001" - const newVersionTarget = stateP.versionIndex; + // The source index .kibana is pointing to. E.g: ".kibana_8.7.0_001" + const source = aliases[stateP.currentAlias]; + // The target index .kibana WILL be pointing to if we reindex. E.g: ".kibana_8.8.0_001" + const newVersionTarget = stateP.versionIndex; - const postInitState = { - aliases, - sourceIndex: Option.fromNullable(source), - sourceIndexMappings: Option.fromNullable(source ? indices[source]?.mappings : undefined), - versionIndexReadyActions: Option.none, - }; + const postInitState = { + aliases, + sourceIndex: Option.fromNullable(source), + sourceIndexMappings: Option.fromNullable(source ? indices[source]?.mappings : undefined), + versionIndexReadyActions: Option.none, + }; - if ( - // Don't actively participate in this migration but wait for another instance to complete it - stateP.waitForMigrationCompletion === true - ) { - return { - ...stateP, - ...postInitState, - sourceIndex: Option.none, - targetIndex: newVersionTarget, - controlState: 'WAIT_FOR_MIGRATION_COMPLETION', - // Wait for 2s before checking again if the migration has completed - retryDelay: 2000, - logs: [ - ...stateP.logs, - { - level: 'info', - message: `Migration required. Waiting until another Kibana instance completes the migration.`, - }, - ], - }; - } else if ( - // If the `.kibana` alias exists - Option.isSome(postInitState.sourceIndex) - ) { - return { - ...stateP, - ...postInitState, - controlState: 'WAIT_FOR_YELLOW_SOURCE', - sourceIndex: postInitState.sourceIndex, - sourceIndexMappings: postInitState.sourceIndexMappings as Option.Some, - targetIndex: postInitState.sourceIndex.value, // We preserve the same index, source == target (E.g: ".xx8.7.0_001") - }; - } else if (indices[stateP.legacyIndex] != null) { - // Migrate from a legacy index + if ( + // Don't actively participate in this migration but wait for another instance to complete it + stateP.waitForMigrationCompletion === true + ) { + return { + ...stateP, + ...postInitState, + sourceIndex: Option.none, + targetIndex: newVersionTarget, + controlState: 'WAIT_FOR_MIGRATION_COMPLETION', + // Wait for 2s before checking again if the migration has completed + retryDelay: 2000, + logs: [ + ...stateP.logs, + { + level: 'info', + message: `Migration required. Waiting until another Kibana instance completes the migration.`, + }, + ], + }; + } else if ( + // If the `.kibana` alias exists + Option.isSome(postInitState.sourceIndex) + ) { + return { + ...stateP, + ...postInitState, + controlState: 'WAIT_FOR_YELLOW_SOURCE', + sourceIndex: postInitState.sourceIndex, + sourceIndexMappings: postInitState.sourceIndexMappings as Option.Some, + targetIndex: postInitState.sourceIndex.value, // We preserve the same index, source == target (E.g: ".xx8.7.0_001") + }; + } else if (indices[stateP.legacyIndex] != null) { + // Migrate from a legacy index - // If the user used default index names we can narrow the version - // number we use when creating a backup index. This is purely to help - // users more easily identify how "old" and index is so that they can - // decide if it's safe to delete these rollback backups. Because - // backups are kept for rollback, a version number is more useful than - // a date. - let legacyVersion = ''; - if (stateP.indexPrefix === '.kibana') { - legacyVersion = 'pre6.5.0'; - } else if (stateP.indexPrefix === '.kibana_task_manager') { - legacyVersion = 'pre7.4.0'; - } else { - legacyVersion = 'pre' + stateP.kibanaVersion; - } + // If the user used default index names we can narrow the version + // number we use when creating a backup index. This is purely to help + // users more easily identify how "old" and index is so that they can + // decide if it's safe to delete these rollback backups. Because + // backups are kept for rollback, a version number is more useful than + // a date. + let legacyVersion = ''; + if (stateP.indexPrefix === '.kibana') { + legacyVersion = 'pre6.5.0'; + } else if (stateP.indexPrefix === '.kibana_task_manager') { + legacyVersion = 'pre7.4.0'; + } else { + legacyVersion = 'pre' + stateP.kibanaVersion; + } - const legacyReindexTarget = `${stateP.indexPrefix}_${legacyVersion}_001`; + const legacyReindexTarget = `${stateP.indexPrefix}_${legacyVersion}_001`; - return { - ...stateP, - ...postInitState, - controlState: 'LEGACY_SET_WRITE_BLOCK', - sourceIndex: Option.some(legacyReindexTarget) as Option.Some, - sourceIndexMappings: Option.some( - indices[stateP.legacyIndex].mappings - ) as Option.Some, - targetIndex: newVersionTarget, - legacyPreMigrationDoneActions: [ - { remove_index: { index: stateP.legacyIndex } }, - { - add: { - index: legacyReindexTarget, - alias: stateP.currentAlias, - }, + return { + ...stateP, + ...postInitState, + controlState: 'LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION', + sourceIndex: Option.some(legacyReindexTarget) as Option.Some, + sourceIndexMappings: Option.some( + indices[stateP.legacyIndex].mappings + ) as Option.Some, + targetIndex: newVersionTarget, + legacyPreMigrationDoneActions: [ + { remove_index: { index: stateP.legacyIndex } }, + { + add: { + index: legacyReindexTarget, + alias: stateP.currentAlias, }, - ], - versionIndexReadyActions: Option.some([ - { - remove: { - index: legacyReindexTarget, - alias: stateP.currentAlias, - must_exist: true, - }, + }, + ], + versionIndexReadyActions: Option.some([ + { + remove: { + index: legacyReindexTarget, + alias: stateP.currentAlias, + must_exist: true, }, - { add: { index: newVersionTarget, alias: stateP.currentAlias } }, - { add: { index: newVersionTarget, alias: stateP.versionAlias } }, - { remove_index: { index: stateP.tempIndex } }, - ]), - }; - } else if ( - // if we must relocate documents to this migrator's index, but the index does NOT yet exist: - // this migrator must create a temporary index and synchronize with other migrators - // this is a similar flow to the reindex one, but this migrator will not reindexing anything - stateP.mustRelocateDocuments - ) { - return { - ...stateP, - ...postInitState, - controlState: 'CREATE_REINDEX_TEMP', - sourceIndex: Option.none as Option.None, - targetIndex: newVersionTarget, - versionIndexReadyActions: Option.some([ - { add: { index: newVersionTarget, alias: stateP.currentAlias } }, - { add: { index: newVersionTarget, alias: stateP.versionAlias } }, - { remove_index: { index: stateP.tempIndex } }, - ]), - }; - } else { - // no need to copy anything over from other indices, we can start with a clean, empty index - return { - ...stateP, - ...postInitState, - controlState: 'CREATE_NEW_TARGET', - sourceIndex: Option.none as Option.None, - targetIndex: newVersionTarget, - versionIndexReadyActions: Option.some([ - { add: { index: newVersionTarget, alias: stateP.currentAlias } }, - { add: { index: newVersionTarget, alias: stateP.versionAlias } }, - ]) as Option.Some, - }; - } + }, + { add: { index: newVersionTarget, alias: stateP.currentAlias } }, + { add: { index: newVersionTarget, alias: stateP.versionAlias } }, + { remove_index: { index: stateP.tempIndex } }, + ]), + }; + } else if ( + // if we must relocate documents to this migrator's index, but the index does NOT yet exist: + // this migrator must create a temporary index and synchronize with other migrators + // this is a similar flow to the reindex one, but this migrator will not reindexing anything + stateP.mustRelocateDocuments + ) { + return { + ...stateP, + ...postInitState, + controlState: 'CREATE_REINDEX_TEMP', + sourceIndex: Option.none as Option.None, + targetIndex: newVersionTarget, + versionIndexReadyActions: Option.some([ + { add: { index: newVersionTarget, alias: stateP.currentAlias } }, + { add: { index: newVersionTarget, alias: stateP.versionAlias } }, + { remove_index: { index: stateP.tempIndex } }, + ]), + }; } else { - throwBadResponse(stateP, res); + // no need to copy anything over from other indices, we can start with a clean, empty index + return { + ...stateP, + ...postInitState, + controlState: 'CREATE_NEW_TARGET', + sourceIndex: Option.none as Option.None, + targetIndex: newVersionTarget, + versionIndexReadyActions: Option.some([ + { add: { index: newVersionTarget, alias: stateP.currentAlias } }, + { add: { index: newVersionTarget, alias: stateP.versionAlias } }, + ]) as Option.Some, + }; } } else if (stateP.controlState === 'WAIT_FOR_MIGRATION_COMPLETION') { const res = resW as ExcludeRetryableEsError>; @@ -306,6 +294,22 @@ export const model = (currentState: State, resW: ResponseType): ], }; } + } else if (stateP.controlState === 'LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION') { + const res = resW as ExcludeRetryableEsError>; + if (Either.isRight(res)) { + return { + ...stateP, + controlState: 'LEGACY_SET_WRITE_BLOCK', + }; + } else { + const left = res.left; + if (isTypeof(left, 'incompatible_cluster_routing_allocation')) { + const retryErrorMessage = `[${left.type}] Incompatible Elasticsearch cluster settings detected. Remove the persistent and transient Elasticsearch cluster setting 'cluster.routing.allocation.enable' or set it to a value of 'all' to allow migrations to proceed. Refer to ${stateP.migrationDocLinks.routingAllocationDisabled} for more information on how to resolve the issue.`; + return delayRetryState(stateP, retryErrorMessage, stateP.retryAttempts); + } else { + throwBadResponse(stateP, left); + } + } } else if (stateP.controlState === 'LEGACY_SET_WRITE_BLOCK') { const res = resW as ExcludeRetryableEsError>; // If the write block is successfully in place @@ -457,7 +461,7 @@ export const model = (currentState: State, resW: ResponseType): // we must reindex and synchronize with other migrators return { ...stateP, - controlState: 'CHECK_UNKNOWN_DOCUMENTS', + controlState: 'CHECK_CLUSTER_ROUTING_ALLOCATION', }; } else { // this migrator is not involved in a relocation, we can proceed with the standard flow @@ -502,7 +506,7 @@ export const model = (currentState: State, resW: ResponseType): case MigrationType.Incompatible: return { ...stateP, - controlState: 'CHECK_UNKNOWN_DOCUMENTS', + controlState: 'CHECK_CLUSTER_ROUTING_ALLOCATION', }; case MigrationType.Unnecessary: return { @@ -636,7 +640,7 @@ export const model = (currentState: State, resW: ResponseType): ...stateP, controlState: stateP.mustRefresh ? 'REFRESH_SOURCE' : 'OUTDATED_DOCUMENTS_SEARCH_OPEN_PIT', }; - } else if (Either.isLeft(res)) { + } else { const left = res.left; // Note: if multiple newer Kibana versions are competing with each other to perform a migration, // it might happen that another Kibana instance has deleted this instance's version index. @@ -661,11 +665,8 @@ export const model = (currentState: State, resW: ResponseType): // step). throwBadResponse(stateP, left as never); } else { - // TODO update to handle 2 more cases throwBadResponse(stateP, left); } - } else { - throwBadResponse(stateP, res); } } else if (stateP.controlState === 'REFRESH_SOURCE') { const res = resW as ExcludeRetryableEsError>; @@ -677,6 +678,22 @@ export const model = (currentState: State, resW: ResponseType): } else { throwBadResponse(stateP, res); } + } else if (stateP.controlState === 'CHECK_CLUSTER_ROUTING_ALLOCATION') { + const res = resW as ExcludeRetryableEsError>; + if (Either.isRight(res)) { + return { + ...stateP, + controlState: 'CHECK_UNKNOWN_DOCUMENTS', + }; + } else { + const left = res.left; + if (isTypeof(left, 'incompatible_cluster_routing_allocation')) { + const retryErrorMessage = `[${left.type}] Incompatible Elasticsearch cluster settings detected. Remove the persistent and transient Elasticsearch cluster setting 'cluster.routing.allocation.enable' or set it to a value of 'all' to allow migrations to proceed. Refer to ${stateP.migrationDocLinks.routingAllocationDisabled} for more information on how to resolve the issue.`; + return delayRetryState(stateP, retryErrorMessage, stateP.retryAttempts); + } else { + throwBadResponse(stateP, left); + } + } } else if (stateP.controlState === 'CHECK_UNKNOWN_DOCUMENTS') { const res = resW as ExcludeRetryableEsError>; @@ -1304,11 +1321,11 @@ export const model = (currentState: State, resW: ResponseType): Either.isRight(res) || (isTypeof(res.left, 'documents_transform_failed') && stateP.discardCorruptObjects) ) { - // we might have some transformation errors, but user has chosen to discard them if ( (stateP.corruptDocumentIds.length === 0 && stateP.transformErrors.length === 0) || stateP.discardCorruptObjects ) { + // we might have some transformation errors from previous iterations, but user has chosen to discard them const documents = Either.isRight(res) ? res.right.processedDocs : res.left.processedDocs; let corruptDocumentIds = stateP.corruptDocumentIds; @@ -1346,8 +1363,10 @@ export const model = (currentState: State, resW: ResponseType): }; } } else { - // We have seen corrupt documents and/or transformation errors - // skip indexing and go straight to reading and transforming more docs + // At this point, there are some corrupt documents and/or transformation errors + // from previous iterations and we're not discarding them. + // Also, the current batch of SEARCH_READ documents has been transformed successfully + // so there is no need to append them to the lists of corruptDocumentIds, transformErrors. return { ...stateP, controlState: 'OUTDATED_DOCUMENTS_SEARCH_READ', diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts index 9f7da4a10c2e81..2ab4a0d927b842 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts @@ -80,7 +80,7 @@ export const nextActionMap = ( ) => { return { INIT: (state: InitState) => - Actions.initAction({ client, indices: [state.currentAlias, state.versionAlias] }), + Actions.fetchIndices({ client, indices: [state.currentAlias, state.versionAlias] }), WAIT_FOR_MIGRATION_COMPLETION: (state: WaitForMigrationCompletionState) => Actions.fetchIndices({ client, indices: [state.currentAlias, state.versionAlias] }), WAIT_FOR_YELLOW_SOURCE: (state: WaitForYellowSourceState) => @@ -117,6 +117,7 @@ export const nextActionMap = ( Actions.updateAliases({ client, aliasActions: state.preTransformDocsActions }), REFRESH_SOURCE: (state: RefreshSource) => Actions.refreshIndex({ client, index: state.sourceIndex.value }), + CHECK_CLUSTER_ROUTING_ALLOCATION: () => Actions.checkClusterRoutingAllocationEnabled(client), CHECK_UNKNOWN_DOCUMENTS: (state: CheckUnknownDocumentsState) => Actions.checkForUnknownDocs({ client, @@ -287,6 +288,8 @@ export const nextActionMap = ( ), MARK_VERSION_INDEX_READY_CONFLICT: (state: MarkVersionIndexReadyConflict) => Actions.fetchIndices({ client, indices: [state.currentAlias, state.versionAlias] }), + LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION: () => + Actions.checkClusterRoutingAllocationEnabled(client), LEGACY_SET_WRITE_BLOCK: (state: LegacySetWriteBlockState) => Actions.setWriteBlock({ client, index: state.legacyIndex }), LEGACY_CREATE_REINDEX_TARGET: (state: LegacyCreateReindexTargetState) => diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/state.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/state.ts index b26088adc53e9d..fc32f88ddd910c 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/state.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/state.ts @@ -384,6 +384,10 @@ export interface RefreshTarget extends PostInitState { readonly targetIndex: string; } +export interface CheckClusterRoutingAllocationState extends SourceExistsState { + readonly controlState: 'CHECK_CLUSTER_ROUTING_ALLOCATION'; +} + export interface CheckTargetTypesMappingsState extends PostInitState { readonly controlState: 'CHECK_TARGET_MAPPINGS'; } @@ -510,6 +514,10 @@ export interface LegacyBaseState extends SourceExistsState { readonly legacyPreMigrationDoneActions: AliasAction[]; } +export interface LegacyCheckClusterRoutingAllocationState extends LegacyBaseState { + readonly controlState: 'LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION'; +} + export interface LegacySetWriteBlockState extends LegacyBaseState { /** Set a write block on the legacy index to prevent any further writes */ readonly controlState: 'LEGACY_SET_WRITE_BLOCK'; @@ -549,6 +557,7 @@ export interface LegacyDeleteState extends LegacyBaseState { export type State = Readonly< | CalculateExcludeFiltersState + | CheckClusterRoutingAllocationState | CheckTargetTypesMappingsState | CheckUnknownDocumentsState | CheckVersionIndexReadyActions @@ -561,6 +570,7 @@ export type State = Readonly< | DoneState | FatalState | InitState + | LegacyCheckClusterRoutingAllocationState | LegacyCreateReindexTargetState | LegacyDeleteState | LegacyReindexState diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/actions/index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/actions/index.ts index a3db45a3748cc3..c586d9f3b95df8 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/actions/index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/actions/index.ts @@ -9,7 +9,7 @@ import type { ActionErrorTypeMap as BaseActionErrorTypeMap } from '../../actions'; export { - initAction as init, + fetchIndices, waitForIndexStatus, createIndex, updateAliases, @@ -25,7 +25,6 @@ export { transformDocs, bulkOverwriteTransformedDocuments, noop, - type InitActionParams, type IncompatibleClusterRoutingAllocation, type RetryableEsClientError, type WaitForTaskCompletionTimeout, diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/model.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/model.test.ts index 0ba01a714b99de..36eb685226ce41 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/model.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/model.test.ts @@ -9,7 +9,7 @@ import './model.test.mocks'; import * as Either from 'fp-ts/lib/Either'; import { createContextMock, MockedMigratorContext } from '../test_helpers'; -import type { RetryableEsClientError } from '../../actions'; +import type { FetchIndexResponse, RetryableEsClientError } from '../../actions'; import type { State, BaseState, FatalState, AllActionStates } from '../state'; import type { StateActionResponse } from './types'; import { model, modelStageMap } from './model'; @@ -89,7 +89,7 @@ describe('model', () => { mappings: { properties: {} }, settings: {}, }, - }); + }) as Either.Right; const newState = model(state, res, context); expect(newState.retryCount).toEqual(0); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.ts index 892ac57c7e79c5..383b8dd583d416 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.ts @@ -75,24 +75,12 @@ describe('Stage: init', () => { }); }); - it('INIT -> INIT when cluster routing allocation is incompatible', () => { - const state = createState(); - const res: StateActionResponse<'INIT'> = Either.left({ - type: 'incompatible_cluster_routing_allocation', - }); - - const newState = init(state, res, context); - - expect(newState.controlState).toEqual('INIT'); - expect(newState.retryCount).toEqual(1); - expect(newState.retryDelay).toEqual(2000); - expect(newState.logs).toHaveLength(1); - }); - it('calls getCurrentIndex with the correct parameters', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; const aliases = { '.foo': '.bar' }; getAliasesMock.mockReturnValue(Either.right(aliases)); @@ -110,7 +98,9 @@ describe('Stage: init', () => { it('calls checkVersionCompatibility with the correct parameters', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; init(state, res, context); @@ -130,7 +120,9 @@ describe('Stage: init', () => { it('adds a log entry about the algo check', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; const newState = init(state, res, context); @@ -142,7 +134,9 @@ describe('Stage: init', () => { it('INIT -> FATAL', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; const newState = init(state, res, context); @@ -162,7 +156,9 @@ describe('Stage: init', () => { it('adds a log entry about the algo check', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; const newState = init(state, res, context); @@ -174,7 +170,9 @@ describe('Stage: init', () => { it('INIT -> FATAL', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; const newState = init(state, res, context); @@ -195,7 +193,9 @@ describe('Stage: init', () => { it('calls buildIndexMappings with the correct parameters', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; init(state, res, context); @@ -207,7 +207,9 @@ describe('Stage: init', () => { it('adds a log entry about the algo check', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; const newState = init(state, res, context); @@ -219,7 +221,9 @@ describe('Stage: init', () => { it('INIT -> UPDATE_INDEX_MAPPINGS', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; const mockMappings = { properties: { someMappings: 'string' } }; buildIndexMappingsMock.mockReturnValue(mockMappings); @@ -248,7 +252,9 @@ describe('Stage: init', () => { it('adds a log entry about the algo check', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; const newState = init(state, res, context); @@ -260,7 +266,9 @@ describe('Stage: init', () => { it('INIT -> UPDATE_INDEX_MAPPINGS', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; const mockMappings = { properties: { someMappings: 'string' } }; buildIndexMappingsMock.mockReturnValue(mockMappings); @@ -285,7 +293,9 @@ describe('Stage: init', () => { it('adds a log entry about the algo check', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; const newState = init(state, res, context); @@ -302,7 +312,9 @@ describe('Stage: init', () => { it('calls buildIndexMappings with the correct parameters', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; init(state, res, context); @@ -315,7 +327,9 @@ describe('Stage: init', () => { it('calls getCreationAliases with the correct parameters', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; init(state, res, context); @@ -329,7 +343,9 @@ describe('Stage: init', () => { it('INIT -> CREATE_TARGET_INDEX', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; const mockMappings = { properties: { someMappings: 'string' } }; buildIndexMappingsMock.mockReturnValue(mockMappings); @@ -354,7 +370,9 @@ describe('Stage: init', () => { it('calls generateAdditiveMappingDiff with the correct parameters', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'greater', @@ -373,7 +391,9 @@ describe('Stage: init', () => { it('INIT -> UPDATE_INDEX_MAPPINGS', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'greater', @@ -396,7 +416,9 @@ describe('Stage: init', () => { it('adds a log entry about the version check', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'greater', @@ -414,7 +436,9 @@ describe('Stage: init', () => { it('INIT -> UPDATE_ALIASES if alias actions are not empty', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'equal', @@ -437,7 +461,9 @@ describe('Stage: init', () => { it('INIT -> INDEX_STATE_UPDATE_DONE if alias actions are empty', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'equal', @@ -459,7 +485,9 @@ describe('Stage: init', () => { it('adds a log entry about the version check', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'equal', @@ -477,7 +505,9 @@ describe('Stage: init', () => { it('INIT -> INDEX_STATE_UPDATE_DONE', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'lesser', @@ -494,7 +524,9 @@ describe('Stage: init', () => { it('adds a log entry about the version check', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'lesser', @@ -512,7 +544,9 @@ describe('Stage: init', () => { it('INIT -> FATAL', () => { const state = createState(); const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right( + fetchIndexResponse + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'conflict', @@ -530,7 +564,9 @@ describe('Stage: init', () => { it('adds a log entry about the version check', () => { const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + const res: StateActionResponse<'INIT'> = Either.right( + createResponse() + ) as Either.Right; checkVersionCompatibilityMock.mockReturnValue({ status: 'conflict', diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.ts index 7405515c88b56c..317090b41354b5 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.ts @@ -8,10 +8,7 @@ import { cloneDeep } from 'lodash'; import * as Either from 'fp-ts/lib/Either'; -import { delayRetryState } from '../../../model/retry_state'; -import { throwBadResponse } from '../../../model/helpers'; import type { MigrationLog } from '../../../types'; -import { isTypeof } from '../../actions'; import { getAliases } from '../../../model/helpers'; import { getCurrentIndex, @@ -33,16 +30,6 @@ export const init: ModelStage< | 'INDEX_STATE_UPDATE_DONE' | 'FATAL' > = (state, res, context) => { - if (Either.isLeft(res)) { - const left = res.left; - if (isTypeof(left, 'incompatible_cluster_routing_allocation')) { - const retryErrorMessage = `[${left.type}] Incompatible Elasticsearch cluster settings detected. Remove the persistent and transient Elasticsearch cluster setting 'cluster.routing.allocation.enable' or set it to a value of 'all' to allow migrations to proceed. Refer to ${context.migrationDocLinks.routingAllocationDisabled} for more information on how to resolve the issue.`; - return delayRetryState(state, retryErrorMessage, context.maxRetryAttempts); - } else { - return throwBadResponse(state, left); - } - } - const types = context.types.map((type) => context.typeRegistry.getType(type)!); const logs: MigrationLog[] = [...state.logs]; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/next.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/next.ts index 3073dd66e73f14..56ebb8d721cfa2 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/next.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/next.ts @@ -57,7 +57,7 @@ export const nextActionMap = (context: MigratorContext) => { const client = context.elasticsearchClient; return { INIT: (state: InitState) => - Actions.init({ + Actions.fetchIndices({ client, indices: [`${context.indexPrefix}_*`], }), diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts index 2b6c7136519ffe..64342b3b63d1f0 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts @@ -39,11 +39,12 @@ import { removeWriteBlock, transformDocs, waitForIndexStatus, - initAction, + fetchIndices, cloneIndex, type DocumentsTransformFailed, type DocumentsTransformSuccess, createBulkIndexOperationTuple, + checkClusterRoutingAllocationEnabled, } from '@kbn/core-saved-objects-migration-server-internal'; const { startES } = createTestServers({ @@ -132,7 +133,7 @@ describe('migration actions', () => { await esServer.stop(); }); - describe('initAction', () => { + describe('fetchIndices', () => { afterAll(async () => { await client.cluster.putSettings({ body: { @@ -145,7 +146,7 @@ describe('migration actions', () => { }); it('resolves right empty record if no indices were found', async () => { expect.assertions(1); - const task = initAction({ client, indices: ['no_such_index'] }); + const task = fetchIndices({ client, indices: ['no_such_index'] }); await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", @@ -155,7 +156,7 @@ describe('migration actions', () => { }); it('resolves right record with found indices', async () => { expect.assertions(1); - const res = (await initAction({ + const res = (await fetchIndices({ client, indices: ['no_such_index', 'existing_index_with_docs'], })()) as Either.Right; @@ -174,7 +175,7 @@ describe('migration actions', () => { }); it('includes the _meta data of the indices in the response', async () => { expect.assertions(1); - const res = (await initAction({ + const res = (await fetchIndices({ client, indices: ['existing_index_with_docs'], })()) as Either.Right; @@ -200,6 +201,9 @@ describe('migration actions', () => { }) ); }); + }); + + describe('checkClusterRoutingAllocation', () => { it('resolves left when cluster.routing.allocation.enabled is incompatible', async () => { expect.assertions(3); await client.cluster.putSettings({ @@ -210,10 +214,7 @@ describe('migration actions', () => { }, }, }); - const task = initAction({ - client, - indices: ['existing_index_with_docs'], - }); + const task = checkClusterRoutingAllocationEnabled(client); await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", @@ -230,10 +231,7 @@ describe('migration actions', () => { }, }, }); - const task2 = initAction({ - client, - indices: ['existing_index_with_docs'], - }); + const task2 = checkClusterRoutingAllocationEnabled(client); await expect(task2()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", @@ -250,10 +248,7 @@ describe('migration actions', () => { }, }, }); - const task3 = initAction({ - client, - indices: ['existing_index_with_docs'], - }); + const task3 = checkClusterRoutingAllocationEnabled(client); await expect(task3()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", @@ -272,10 +267,7 @@ describe('migration actions', () => { }, }, }); - const task = initAction({ - client, - indices: ['existing_index_with_docs'], - }); + const task = checkClusterRoutingAllocationEnabled(client); const result = await task(); expect(Either.isRight(result)).toBe(true); }); diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts index c114293823cb75..92b470288d3278 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts @@ -39,11 +39,12 @@ import { removeWriteBlock, transformDocs, waitForIndexStatus, - initAction, + fetchIndices, cloneIndex, type DocumentsTransformFailed, type DocumentsTransformSuccess, createBulkIndexOperationTuple, + checkClusterRoutingAllocationEnabled, } from '@kbn/core-saved-objects-migration-server-internal'; interface EsServer { @@ -169,7 +170,7 @@ export const runActionTestSuite = ({ await esServer.stop(); }); - describe('initAction', () => { + describe('fetchIndices', () => { afterAll(async () => { await client.cluster.putSettings({ body: { @@ -182,7 +183,7 @@ export const runActionTestSuite = ({ }); it('resolves right empty record if no indices were found', async () => { expect.assertions(1); - const task = initAction({ client, indices: ['no_such_index'] }); + const task = fetchIndices({ client, indices: ['no_such_index'] }); await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Right", @@ -192,7 +193,7 @@ export const runActionTestSuite = ({ }); it('resolves right record with found indices', async () => { expect.assertions(1); - const res = (await initAction({ + const res = (await fetchIndices({ client, indices: ['no_such_index', 'existing_index_with_docs'], })()) as Either.Right; @@ -211,7 +212,7 @@ export const runActionTestSuite = ({ }); it('includes the _meta data of the indices in the response', async () => { expect.assertions(1); - const res = (await initAction({ + const res = (await fetchIndices({ client, indices: ['existing_index_with_docs'], })()) as Either.Right; @@ -237,6 +238,9 @@ export const runActionTestSuite = ({ }) ); }); + }); + + describe('checkClusterRoutingAllocation', () => { it('resolves left when cluster.routing.allocation.enabled is incompatible', async () => { expect.assertions(3); await client.cluster.putSettings({ @@ -247,10 +251,7 @@ export const runActionTestSuite = ({ }, }, }); - const task = initAction({ - client, - indices: ['existing_index_with_docs'], - }); + const task = checkClusterRoutingAllocationEnabled(client); await expect(task()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", @@ -267,10 +268,7 @@ export const runActionTestSuite = ({ }, }, }); - const task2 = initAction({ - client, - indices: ['existing_index_with_docs'], - }); + const task2 = checkClusterRoutingAllocationEnabled(client); await expect(task2()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", @@ -287,10 +285,7 @@ export const runActionTestSuite = ({ }, }, }); - const task3 = initAction({ - client, - indices: ['existing_index_with_docs'], - }); + const task3 = checkClusterRoutingAllocationEnabled(client); await expect(task3()).resolves.toMatchInlineSnapshot(` Object { "_tag": "Left", @@ -309,10 +304,7 @@ export const runActionTestSuite = ({ }, }, }); - const task = initAction({ - client, - indices: ['existing_index_with_docs'], - }); + const task = checkClusterRoutingAllocationEnabled(client); const result = await task(); expect(Either.isRight(result)).toBe(true); }); diff --git a/src/core/server/integration_tests/saved_objects/migrations/group5/active_delete.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group5/active_delete.test.ts index 37bd9f49a6cd17..d950129dac69a0 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group5/active_delete.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group5/active_delete.test.ts @@ -366,7 +366,10 @@ describe('when upgrading to a new stack version', () => { const logs = await readLog(); expect(logs).toMatch('INIT -> WAIT_FOR_YELLOW_SOURCE'); expect(logs).toMatch('WAIT_FOR_YELLOW_SOURCE -> UPDATE_SOURCE_MAPPINGS_PROPERTIES.'); - expect(logs).toMatch('UPDATE_SOURCE_MAPPINGS_PROPERTIES -> CHECK_UNKNOWN_DOCUMENTS.'); + expect(logs).toMatch( + 'UPDATE_SOURCE_MAPPINGS_PROPERTIES -> CHECK_CLUSTER_ROUTING_ALLOCATION.' + ); + expect(logs).toMatch('CHECK_CLUSTER_ROUTING_ALLOCATION -> CHECK_UNKNOWN_DOCUMENTS.'); expect(logs).toMatch('CHECK_UNKNOWN_DOCUMENTS -> SET_SOURCE_WRITE_BLOCK.'); expect(logs).toMatch('CHECK_TARGET_MAPPINGS -> UPDATE_TARGET_MAPPINGS_PROPERTIES.'); expect(logs).toMatch('UPDATE_TARGET_MAPPINGS_META -> CHECK_VERSION_INDEX_READY_ACTIONS.'); diff --git a/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts index c0a4c73b1664cc..8f765010e37a8b 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts @@ -306,7 +306,8 @@ describe('split .kibana index into multiple system indices', () => { expect(logs).toContainLogEntries( [ // .kibana_task_manager index exists and has no aliases => LEGACY_* migration path - '[.kibana_task_manager] INIT -> LEGACY_SET_WRITE_BLOCK.', + '[.kibana_task_manager] INIT -> LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION.', + '[.kibana_task_manager] LEGACY_CHECK_CLUSTER_ROUTING_ALLOCATION -> LEGACY_SET_WRITE_BLOCK.', '[.kibana_task_manager] LEGACY_REINDEX_WAIT_FOR_TASK -> LEGACY_DELETE.', '[.kibana_task_manager] LEGACY_DELETE -> SET_SOURCE_WRITE_BLOCK.', '[.kibana_task_manager] SET_SOURCE_WRITE_BLOCK -> CALCULATE_EXCLUDE_FILTERS.', @@ -360,7 +361,8 @@ describe('split .kibana index into multiple system indices', () => { expect(logs).toContainLogEntries( [ '[.kibana] INIT -> WAIT_FOR_YELLOW_SOURCE.', - '[.kibana] WAIT_FOR_YELLOW_SOURCE -> CHECK_UNKNOWN_DOCUMENTS.', + '[.kibana] WAIT_FOR_YELLOW_SOURCE -> CHECK_CLUSTER_ROUTING_ALLOCATION.', + '[.kibana] CHECK_CLUSTER_ROUTING_ALLOCATION -> CHECK_UNKNOWN_DOCUMENTS.', '[.kibana] CHECK_UNKNOWN_DOCUMENTS -> SET_SOURCE_WRITE_BLOCK.', '[.kibana] SET_SOURCE_WRITE_BLOCK -> CALCULATE_EXCLUDE_FILTERS.', '[.kibana] CALCULATE_EXCLUDE_FILTERS -> CREATE_REINDEX_TEMP.', diff --git a/src/core/server/integration_tests/saved_objects/migrations/group5/skip_reindex.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group5/skip_reindex.test.ts index 3d383a603a53f5..4d244314d3acb8 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group5/skip_reindex.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group5/skip_reindex.test.ts @@ -104,7 +104,10 @@ describe('when migrating to a new version', () => { const logs = await readLog(); expect(logs).toMatch('INIT -> WAIT_FOR_YELLOW_SOURCE.'); expect(logs).toMatch('WAIT_FOR_YELLOW_SOURCE -> UPDATE_SOURCE_MAPPINGS_PROPERTIES.'); - expect(logs).toMatch('UPDATE_SOURCE_MAPPINGS_PROPERTIES -> CHECK_UNKNOWN_DOCUMENTS.'); + expect(logs).toMatch( + 'UPDATE_SOURCE_MAPPINGS_PROPERTIES -> CHECK_CLUSTER_ROUTING_ALLOCATION.' + ); + expect(logs).toMatch('CHECK_CLUSTER_ROUTING_ALLOCATION -> CHECK_UNKNOWN_DOCUMENTS.'); expect(logs).toMatch('CHECK_TARGET_MAPPINGS -> UPDATE_TARGET_MAPPINGS_PROPERTIES.'); expect(logs).toMatch('UPDATE_TARGET_MAPPINGS_META -> CHECK_VERSION_INDEX_READY_ACTIONS.'); expect(logs).toMatch('CHECK_VERSION_INDEX_READY_ACTIONS -> MARK_VERSION_INDEX_READY.'); From d9fc2ca1edd35c89cf38f9a9f32048d295234355 Mon Sep 17 00:00:00 2001 From: Vadim Kibana <82822460+vadimkibana@users.noreply.github.com> Date: Thu, 20 Jun 2024 09:22:58 +0200 Subject: [PATCH 107/123] [ES|QL] `METRICS` command definition and validation (#184905) ## Summary Partially addresses https://github.com/elastic/kibana/issues/184498 The main contribution of this PR is the `METRICS` command validation cases: image See own-review below for more comments. ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- packages/kbn-esql-ast/index.ts | 1 + .../src/__tests__/ast_parser.metrics.test.ts | 10 +- packages/kbn-esql-ast/src/ast_factory.ts | 16 +- packages/kbn-esql-ast/src/ast_walker.ts | 9 +- packages/kbn-esql-ast/src/types.ts | 6 +- .../README.md | 10 +- .../jest.integration.config.js | 15 + .../scripts/generate_function_definitions.ts | 22 +- .../src/definitions/aggs.ts | 14 +- .../src/definitions/builtin.ts | 4 +- .../src/definitions/commands.ts | 30 + .../src/definitions/functions.ts | 168 +- .../src/shared/helpers.ts | 3 + .../src/shared/variables.ts | 35 +- .../validation/__tests__/callbacks.test.ts | 31 + .../src/validation/__tests__/helpers.ts | 71 + .../test_suites/validation.command.from.ts | 194 + .../test_suites/validation.command.metrics.ts | 293 + .../test_suites/validation.command.stats.ts | 365 + .../src/validation/__tests__/types.ts | 17 + .../__tests__/validation.command.from.test.ts | 12 + .../validation.command.metrics.test.ts | 12 + .../validation.command.stats.test.ts | 12 + .../src/validation/errors.ts | 109 +- .../esql_validation_meta_tests.json | 7675 ++++++++--------- .../src/validation/helpers.ts | 14 +- .../src/validation/types.ts | 20 + .../src/validation/validation.from.test.ts | 49 - .../src/validation/validation.test.ts | 357 +- .../src/validation/validation.ts | 404 +- test/api_integration/apis/esql/errors.ts | 1 + 31 files changed, 5201 insertions(+), 4778 deletions(-) create mode 100644 packages/kbn-esql-validation-autocomplete/jest.integration.config.js create mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/__tests__/callbacks.test.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/__tests__/helpers.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.from.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.metrics.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/__tests__/types.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.from.test.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.metrics.test.ts create mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.stats.test.ts delete mode 100644 packages/kbn-esql-validation-autocomplete/src/validation/validation.from.test.ts diff --git a/packages/kbn-esql-ast/index.ts b/packages/kbn-esql-ast/index.ts index c418110ccab873..fc129c5c6fac3a 100644 --- a/packages/kbn-esql-ast/index.ts +++ b/packages/kbn-esql-ast/index.ts @@ -24,6 +24,7 @@ export type { ESQLLiteral, AstProviderFn, EditorError, + ESQLAstNode, } from './src/types'; // Low level functions to parse grammar diff --git a/packages/kbn-esql-ast/src/__tests__/ast_parser.metrics.test.ts b/packages/kbn-esql-ast/src/__tests__/ast_parser.metrics.test.ts index 43cf738d599aa0..ec56b1d015c648 100644 --- a/packages/kbn-esql-ast/src/__tests__/ast_parser.metrics.test.ts +++ b/packages/kbn-esql-ast/src/__tests__/ast_parser.metrics.test.ts @@ -19,7 +19,7 @@ describe('METRICS', () => { { type: 'command', name: 'metrics', - indices: [ + sources: [ { type: 'source', name: 'foo', @@ -30,7 +30,7 @@ describe('METRICS', () => { ]); }); - it('can parse multiple "indices"', () => { + it('can parse multiple "sources"', () => { const text = 'METRICS foo ,\nbar\t,\t\nbaz \n'; const { ast, errors } = parse(text); @@ -39,7 +39,7 @@ describe('METRICS', () => { { type: 'command', name: 'metrics', - indices: [ + sources: [ { type: 'source', name: 'foo', @@ -69,7 +69,7 @@ describe('METRICS', () => { { type: 'command', name: 'metrics', - indices: [ + sources: [ { type: 'source', name: 'foo', @@ -99,7 +99,7 @@ describe('METRICS', () => { { type: 'command', name: 'metrics', - indices: [ + sources: [ { type: 'source', name: 'foo', diff --git a/packages/kbn-esql-ast/src/ast_factory.ts b/packages/kbn-esql-ast/src/ast_factory.ts index 476b3364f27440..9d76ff3a7cd4d6 100644 --- a/packages/kbn-esql-ast/src/ast_factory.ts +++ b/packages/kbn-esql-ast/src/ast_factory.ts @@ -44,7 +44,7 @@ import { import { getPosition } from './ast_position_utils'; import { collectAllSourceIdentifiers, - collectAllFieldsStatements, + collectAllFields, visitByOption, collectAllColumnIdentifiers, visitRenameClauses, @@ -120,7 +120,7 @@ export class AstListener implements ESQLParserListener { exitRowCommand(ctx: RowCommandContext) { const command = createCommand('row', ctx); this.ast.push(command); - command.args.push(...collectAllFieldsStatements(ctx.fields())); + command.args.push(...collectAllFields(ctx.fields())); } /** @@ -153,20 +153,20 @@ export class AstListener implements ESQLParserListener { ...createAstBaseItem('metrics', ctx), type: 'command', args: [], - indices: ctx + sources: ctx .getTypedRuleContexts(IndexIdentifierContext) .map((sourceCtx) => createSource(sourceCtx)), }; this.ast.push(node); - const aggregates = collectAllFieldsStatements(ctx.fields(0)); - const grouping = collectAllFieldsStatements(ctx.fields(1)); + const aggregates = collectAllFields(ctx.fields(0)); + const grouping = collectAllFields(ctx.fields(1)); if (aggregates && aggregates.length) { node.aggregates = aggregates; } if (grouping && grouping.length) { node.grouping = grouping; } - node.args.push(...node.indices, ...aggregates, ...grouping); + node.args.push(...node.sources, ...aggregates, ...grouping); } /** @@ -176,7 +176,7 @@ export class AstListener implements ESQLParserListener { exitEvalCommand(ctx: EvalCommandContext) { const commandAst = createCommand('eval', ctx); this.ast.push(commandAst); - commandAst.args.push(...collectAllFieldsStatements(ctx.fields())); + commandAst.args.push(...collectAllFields(ctx.fields())); } /** @@ -189,7 +189,7 @@ export class AstListener implements ESQLParserListener { // STATS expression is optional if (ctx._stats) { - command.args.push(...collectAllFieldsStatements(ctx.fields(0))); + command.args.push(...collectAllFields(ctx.fields(0))); } if (ctx._grouping) { command.args.push(...visitByOption(ctx, ctx._stats ? ctx.fields(1) : ctx.fields(0))); diff --git a/packages/kbn-esql-ast/src/ast_walker.ts b/packages/kbn-esql-ast/src/ast_walker.ts index 8584f65bac2b1a..e93c411541feb3 100644 --- a/packages/kbn-esql-ast/src/ast_walker.ts +++ b/packages/kbn-esql-ast/src/ast_walker.ts @@ -90,6 +90,7 @@ import type { ESQLFunction, ESQLCommandOption, ESQLAstItem, + ESQLAstField, ESQLInlineCast, ESQLUnnamedParamLiteral, ESQLPositionalParamLiteral, @@ -547,14 +548,14 @@ export function visitField(ctx: FieldContext) { return collectBooleanExpression(ctx.booleanExpression()); } -export function collectAllFieldsStatements(ctx: FieldsContext | undefined): ESQLAstItem[] { - const ast: ESQLAstItem[] = []; +export function collectAllFields(ctx: FieldsContext | undefined): ESQLAstField[] { + const ast: ESQLAstField[] = []; if (!ctx) { return ast; } try { for (const field of ctx.field_list()) { - ast.push(...visitField(field)); + ast.push(...(visitField(field) as ESQLAstField[])); } } catch (e) { // do nothing @@ -567,7 +568,7 @@ export function visitByOption(ctx: StatsCommandContext, expr: FieldsContext | un return []; } const option = createOption(ctx.BY()!.getText().toLowerCase(), ctx); - option.args.push(...collectAllFieldsStatements(expr)); + option.args.push(...collectAllFields(expr)); return [option]; } diff --git a/packages/kbn-esql-ast/src/types.ts b/packages/kbn-esql-ast/src/types.ts index ebea0aeeb89f0a..5c6b1d2fdbb8f4 100644 --- a/packages/kbn-esql-ast/src/types.ts +++ b/packages/kbn-esql-ast/src/types.ts @@ -46,9 +46,9 @@ export interface ESQLCommand extends ESQLAstBaseItem { } export interface ESQLAstMetricsCommand extends ESQLCommand<'metrics'> { - indices: ESQLSource[]; - aggregates?: ESQLAstItem[]; - grouping?: ESQLAstItem[]; + sources: ESQLSource[]; + aggregates?: ESQLAstField[]; + grouping?: ESQLAstField[]; } export interface ESQLCommandOption extends ESQLAstBaseItem { diff --git a/packages/kbn-esql-validation-autocomplete/README.md b/packages/kbn-esql-validation-autocomplete/README.md index fb82a67b9171ff..b5a4fc4d71c614 100644 --- a/packages/kbn-esql-validation-autocomplete/README.md +++ b/packages/kbn-esql-validation-autocomplete/README.md @@ -39,7 +39,7 @@ const myCallbacks = { const { errors, warnings } = await validateQuery("from index | stats 1 + avg(myColumn)", getAstAndSyntaxErrors, undefined, myCallbacks); ``` -If not all callbacks are available it is possible to gracefully degradate the validation experience with the `ignoreOnMissingCallbacks` option: +If not all callbacks are available it is possible to gracefully degrade the validation experience with the `ignoreOnMissingCallbacks` option: ```js import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; @@ -61,7 +61,7 @@ const { errors, warnings } = await validateQuery( #### Autocomplete -This is the complete logic for the ES|QL autocomplete language, it is completely indepedent from the actual editor (i.e. Monaco) and the suggestions reported need to be wrapped against the specific editor shape. +This is the complete logic for the ES|QL autocomplete language, it is completely independent from the actual editor (i.e. Monaco) and the suggestions reported need to be wrapped against the specific editor shape. ```js import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; @@ -207,13 +207,13 @@ The autocomplete/suggest task takes a query as input together with the current c Note that autocomplete works most of the time with incomplete/invalid queries, so some logic to manipulate the query into something valid (see the `EDITOR_MARKER` or the `countBracketsUnclosed` functions for more). Once the AST is produced there's a `getAstContext` function that finds the cursor position node (and its parent command), together with some hint like the type of current context: `expression`, `function`, `newCommand`, `option`. -The most complex case is the `expression` as it can cover a moltitude of cases. The function is highly commented in order to identify the specific cases, but there's probably some obscure area still to comment/clarify. +The most complex case is the `expression` as it can cover a multitude of cases. The function is highly commented in order to identify the specific cases, but there's probably some obscure area still to comment/clarify. -### Adding new commands/options/functions/erc... +### Adding new commands/options/functions/etc... To update the definitions: -1. open either approriate definition file within the `definitions` folder and add a new entry to the relative array +1. open either appropriate definition file within the `definitions` folder and add a new entry to the relative array 2. if you are adding a function, run `yarn maketests` to add a set of fundamental validation tests for the new definition. If any of the suggested tests are wrong, feel free to correct them by hand. If it seems like a general problem, open an issue with the details so that we can update the generator code. 3. write new tests for validation and autocomplete diff --git a/packages/kbn-esql-validation-autocomplete/jest.integration.config.js b/packages/kbn-esql-validation-autocomplete/jest.integration.config.js new file mode 100644 index 00000000000000..25671e51f35637 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/jest.integration.config.js @@ -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 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. + */ + +module.exports = { + preset: '@kbn/test/jest_integration_node', + rootDir: '../..', + roots: ['/packages/kbn-esql-validation-autocomplete'], + openHandlesTimeout: 0, + forceExit: true, +}; diff --git a/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts b/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts index ad9966defd9cb2..6806b11e49807f 100644 --- a/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts +++ b/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts @@ -26,7 +26,7 @@ const aliasTable: Record = { const aliases = new Set(Object.values(aliasTable).flat()); const evalSupportedCommandsAndOptions = { - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], }; @@ -288,8 +288,24 @@ function printGeneratedFunctionsFile(functionDefinitions: FunctionDefinition[]) }`; }; - const fileHeader = `// NOTE: This file is generated by the generate_function_definitions.ts script -// Do not edit it manually + const fileHeader = `/** + * __AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.__ + * + * @note This file is generated by the \`generate_function_definitions.ts\` + * script. Do not edit it manually. + * + * + * + * + * + * + * + * + * + * + * + * + */ import type { ESQLFunction } from '@kbn/esql-ast'; import { i18n } from '@kbn/i18n'; diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/aggs.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/aggs.ts index 2d20b871e251bb..08323d121a88a9 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/aggs.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/aggs.ts @@ -28,7 +28,7 @@ function createNumericAggDefinition({ name, type: 'agg', description, - supportedCommands: ['stats'], + supportedCommands: ['stats', 'metrics'], signatures: [ { params: [ @@ -98,7 +98,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [ defaultMessage: 'Returns the maximum value in a field.', }), type: 'agg', - supportedCommands: ['stats'], + supportedCommands: ['stats', 'metrics'], signatures: [ { params: [{ name: 'column', type: 'number', noNestingFunctions: true }], @@ -117,7 +117,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [ defaultMessage: 'Returns the minimum value in a field.', }), type: 'agg', - supportedCommands: ['stats'], + supportedCommands: ['stats', 'metrics'], signatures: [ { params: [{ name: 'column', type: 'number', noNestingFunctions: true }], @@ -138,7 +138,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [ description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.countDoc', { defaultMessage: 'Returns the count of the values in a field.', }), - supportedCommands: ['stats'], + supportedCommands: ['stats', 'metrics'], signatures: [ { params: [ @@ -164,7 +164,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [ defaultMessage: 'Returns the count of distinct values in a field.', } ), - supportedCommands: ['stats'], + supportedCommands: ['stats', 'metrics'], signatures: [ { params: [ @@ -188,7 +188,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [ defaultMessage: 'Returns the count of distinct values in a field.', } ), - supportedCommands: ['stats'], + supportedCommands: ['stats', 'metrics'], signatures: [ { params: [{ name: 'column', type: 'cartesian_point', noNestingFunctions: true }], @@ -212,7 +212,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [ description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.values', { defaultMessage: 'Returns all values in a group as an array.', }), - supportedCommands: ['stats'], + supportedCommands: ['stats', 'metrics'], signatures: [ { params: [{ name: 'expression', type: 'any', noNestingFunctions: true }], diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts index b430e6e7665dff..a32cba3d191c36 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts @@ -22,7 +22,7 @@ function createMathDefinition( type: 'builtin', name, description, - supportedCommands: ['eval', 'where', 'row', 'stats', 'sort'], + supportedCommands: ['eval', 'where', 'row', 'stats', 'metrics', 'sort'], supportedOptions: ['by'], signatures: types.map((type) => { if (Array.isArray(type)) { @@ -507,7 +507,7 @@ const otherDefinitions: FunctionDefinition[] = [ description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.assignDoc', { defaultMessage: 'Assign (=)', }), - supportedCommands: ['eval', 'stats', 'row', 'dissect', 'where', 'enrich'], + supportedCommands: ['eval', 'stats', 'metrics', 'row', 'dissect', 'where', 'enrich'], supportedOptions: ['by', 'with'], signatures: [ { diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts index 414c0fa6a8a9a0..2485b32837a5bf 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts @@ -88,6 +88,36 @@ export const commandDefinitions: CommandDefinition[] = [ params: [{ name: 'functions', type: 'function' }], }, }, + { + name: 'metrics', + description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.metricsDoc', { + defaultMessage: + 'A metrics-specific source command, use this command to load data from TSDB indices. ' + + 'Similar to STATS command on can calculate aggregate statistics, such as average, count, and sum, over the incoming search results set. ' + + 'When used without a BY clause, only one row is returned, which is the aggregation over the entire incoming search results set. ' + + 'When you use a BY clause, one row is returned for each distinct value in the field specified in the BY clause. ' + + 'The command returns only the fields in the aggregation, and you can use a wide range of statistical functions with the stats command. ' + + 'When you perform more than one aggregation, separate each aggregation with a comma.', + }), + examples: [ + 'metrics index', + 'metrics index, index2', + 'metrics index avg = avg(a)', + 'metrics index sum(b) by b', + 'metrics index, index2 sum(b) by b % 2', + 'metrics [ [ by ]]', + 'metrics src1, src2 agg1, agg2 by field1, field2', + ], + options: [], + modes: [], + signature: { + multipleParams: true, + params: [ + { name: 'index', type: 'source', wildcards: true }, + { name: 'expression', type: 'function', optional: true }, + ], + }, + }, { name: 'stats', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.statsDoc', { diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/functions.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/functions.ts index 6c96111b74d9e1..718174ae09f413 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/functions.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/functions.ts @@ -34,7 +34,7 @@ const absDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -63,7 +63,7 @@ const acosDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=.9\n| EVAL acos=ACOS(a)'], @@ -90,7 +90,7 @@ const asinDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=.9\n| EVAL asin=ASIN(a)'], @@ -117,7 +117,7 @@ const atanDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=12.9\n| EVAL atan=ATAN(a)'], @@ -149,7 +149,7 @@ const atan2Definition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW y=12.9, x=.6\n| EVAL atan2=ATAN2(y, x)'], @@ -176,7 +176,7 @@ const cbrtDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW d = 1000.0\n| EVAL c = cbrt(d)'], @@ -202,7 +202,7 @@ const ceilDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=1.8\n| EVAL a=CEIL(a)'], @@ -235,7 +235,7 @@ const cidrMatchDefinition: FunctionDefinition = { minParams: 2, }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -479,7 +479,7 @@ const concatDefinition: FunctionDefinition = { minParams: 2, }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -507,7 +507,7 @@ const cosDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=1.8 \n| EVAL cos=COS(a)'], @@ -533,7 +533,7 @@ const coshDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=1.8 \n| EVAL cosh=COSH(a)'], @@ -631,7 +631,7 @@ const dateDiffDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -664,7 +664,7 @@ const dateExtractDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -698,7 +698,7 @@ const dateFormatDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -732,7 +732,7 @@ const dateParseDefinition: FunctionDefinition = { returnType: 'date', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW date_string = "2022-05-06"\n| EVAL date = DATE_PARSE("yyyy-MM-dd", date_string)'], @@ -778,7 +778,7 @@ const dateTruncDefinition: FunctionDefinition = { returnType: 'date', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -802,7 +802,7 @@ const eDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW E()'], @@ -834,7 +834,7 @@ const endsWithDefinition: FunctionDefinition = { returnType: 'boolean', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['FROM employees\n| KEEP last_name\n| EVAL ln_E = ENDS_WITH(last_name, "d")'], @@ -860,7 +860,7 @@ const floorDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=1.8\n| EVAL a=FLOOR(a)'], @@ -886,7 +886,7 @@ const fromBase64Definition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['row a = "ZWxhc3RpYw==" \n| eval d = from_base64(a)'], @@ -1016,7 +1016,7 @@ const greatestDefinition: FunctionDefinition = { minParams: 1, }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a = 10, b = 20\n| EVAL g = GREATEST(a, b)'], @@ -1184,7 +1184,7 @@ const leastDefinition: FunctionDefinition = { minParams: 1, }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a = 10, b = 20\n| EVAL l = LEAST(a, b)'], @@ -1216,7 +1216,7 @@ const leftDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -1244,7 +1244,7 @@ const lengthDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['FROM employees\n| KEEP first_name, last_name\n| EVAL fn_length = LENGTH(first_name)'], @@ -1296,7 +1296,7 @@ const locateDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['row a = "hello"\n| eval a_ll = locate(a, "ll")'], @@ -1338,7 +1338,7 @@ const logDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: (fnDef: ESQLFunction) => { const messages = []; @@ -1391,7 +1391,7 @@ const log10Definition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: (fnDef: ESQLFunction) => { const messages = []; @@ -1440,7 +1440,7 @@ const ltrimDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -1635,7 +1635,7 @@ const mvAvgDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=[3, 5, 1, 6]\n| EVAL avg_a = MV_AVG(a)'], @@ -1667,7 +1667,7 @@ const mvConcatDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -1787,7 +1787,7 @@ const mvCountDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=["foo", "zoo", "bar"]\n| EVAL count_a = MV_COUNT(a)'], @@ -1903,7 +1903,7 @@ const mvDedupeDefinition: FunctionDefinition = { returnType: 'version', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=["foo", "foo", "bar", "foo"]\n| EVAL dedupe_a = MV_DEDUPE(a)'], @@ -2020,7 +2020,7 @@ const mvFirstDefinition: FunctionDefinition = { returnType: 'version', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a="foo;bar;baz"\n| EVAL first_a = MV_FIRST(SPLIT(a, ";"))'], @@ -2137,7 +2137,7 @@ const mvLastDefinition: FunctionDefinition = { returnType: 'version', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a="foo;bar;baz"\n| EVAL last_a = MV_LAST(SPLIT(a, ";"))'], @@ -2214,7 +2214,7 @@ const mvMaxDefinition: FunctionDefinition = { returnType: 'version', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -2244,7 +2244,7 @@ const mvMedianDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -2324,7 +2324,7 @@ const mvMinDefinition: FunctionDefinition = { returnType: 'version', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -2544,7 +2544,7 @@ const mvSliceDefinition: FunctionDefinition = { returnType: 'version', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -2659,7 +2659,7 @@ const mvSortDefinition: FunctionDefinition = { returnType: 'version', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a = [4, 2, -3, 2]\n| EVAL sa = mv_sort(a), sd = mv_sort(a, "DESC")'], @@ -2686,7 +2686,7 @@ const mvSumDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=[3, 5, 6]\n| EVAL sum_a = MV_SUM(a)'], @@ -2738,7 +2738,7 @@ const mvZipDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -2760,7 +2760,7 @@ const nowDefinition: FunctionDefinition = { returnType: 'date', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW current_date = NOW()', 'FROM sample_data\n| WHERE @timestamp > NOW() - 1 hour'], @@ -2780,7 +2780,7 @@ const piDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW PI()'], @@ -2811,7 +2811,7 @@ const powDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -2883,7 +2883,7 @@ const replaceDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW str = "Hello World"\n| EVAL str = REPLACE(str, "World", "Universe")\n| KEEP str'], @@ -2915,7 +2915,7 @@ const rightDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -2959,7 +2959,7 @@ const roundDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -2987,7 +2987,7 @@ const rtrimDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -3016,7 +3016,7 @@ const signumDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW d = 100.0\n| EVAL s = SIGNUM(d)'], @@ -3042,7 +3042,7 @@ const sinDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=1.8 \n| EVAL sin=SIN(a)'], @@ -3068,7 +3068,7 @@ const sinhDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=1.8 \n| EVAL sinh=SINH(a)'], @@ -3099,7 +3099,7 @@ const splitDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW words="foo;bar;baz;qux;quux;corge"\n| EVAL word = SPLIT(words, ";")'], @@ -3126,7 +3126,7 @@ const sqrtDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW d = 100.0\n| EVAL s = SQRT(d)'], @@ -3263,7 +3263,7 @@ const stContainsDefinition: FunctionDefinition = { returnType: 'boolean', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -3402,7 +3402,7 @@ const stDisjointDefinition: FunctionDefinition = { returnType: 'boolean', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -3541,7 +3541,7 @@ const stIntersectsDefinition: FunctionDefinition = { returnType: 'boolean', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -3680,7 +3680,7 @@ const stWithinDefinition: FunctionDefinition = { returnType: 'boolean', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -3719,7 +3719,7 @@ const stXDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -3758,7 +3758,7 @@ const stYDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -3792,7 +3792,7 @@ const startsWithDefinition: FunctionDefinition = { returnType: 'boolean', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['FROM employees\n| KEEP last_name\n| EVAL ln_S = STARTS_WITH(last_name, "B")'], @@ -3829,7 +3829,7 @@ const substringDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -3859,7 +3859,7 @@ const tanDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=1.8 \n| EVAL tan=TAN(a)'], @@ -3885,7 +3885,7 @@ const tanhDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=1.8 \n| EVAL tanh=TANH(a)'], @@ -3905,7 +3905,7 @@ const tauDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW TAU()'], @@ -3931,7 +3931,7 @@ const toBase64Definition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['row a = "elastic" \n| eval e = to_base64(a)'], @@ -3978,7 +3978,7 @@ const toBooleanDefinition: FunctionDefinition = { returnType: 'boolean', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW str = ["true", "TRuE", "false", "", "yes", "1"]\n| EVAL bool = TO_BOOLEAN(str)'], @@ -4018,7 +4018,7 @@ const toCartesianpointDefinition: FunctionDefinition = { returnType: 'cartesian_point', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -4070,7 +4070,7 @@ const toCartesianshapeDefinition: FunctionDefinition = { returnType: 'cartesian_shape', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -4119,7 +4119,7 @@ const toDatetimeDefinition: FunctionDefinition = { returnType: 'date', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -4148,7 +4148,7 @@ const toDegreesDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW rad = [1.57, 3.14, 4.71]\n| EVAL deg = TO_DEGREES(rad)'], @@ -4205,7 +4205,7 @@ const toDoubleDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -4244,7 +4244,7 @@ const toGeopointDefinition: FunctionDefinition = { returnType: 'geo_point', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW wkt = "POINT(42.97109630194 14.7552534413725)"\n| EVAL pt = TO_GEOPOINT(wkt)'], @@ -4291,7 +4291,7 @@ const toGeoshapeDefinition: FunctionDefinition = { returnType: 'geo_shape', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -4350,7 +4350,7 @@ const toIntegerDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW long = [5013792, 2147483647, 501379200000]\n| EVAL int = TO_INTEGER(long)'], @@ -4386,7 +4386,7 @@ const toIpDefinition: FunctionDefinition = { returnType: 'ip', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -4445,7 +4445,7 @@ const toLongDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -4473,7 +4473,7 @@ const toLowerDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW message = "Some Text"\n| EVAL message_lower = TO_LOWER(message)'], @@ -4499,7 +4499,7 @@ const toRadiansDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW deg = [90.0, 180.0, 270.0]\n| EVAL rad = TO_RADIANS(deg)'], @@ -4615,7 +4615,7 @@ const toStringDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW a=10\n| EVAL j = TO_STRING(a)', 'ROW a=[10, 9, 8]\n| EVAL j = TO_STRING(a)'], @@ -4675,7 +4675,7 @@ const toUnsignedLongDefinition: FunctionDefinition = { returnType: 'number', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -4703,7 +4703,7 @@ const toUpperDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW message = "Some Text"\n| EVAL message_upper = TO_UPPER(message)'], @@ -4739,7 +4739,7 @@ const toVersionDefinition: FunctionDefinition = { returnType: 'version', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: ['ROW v = TO_VERSION("1.2.3")'], @@ -4765,7 +4765,7 @@ const trimDefinition: FunctionDefinition = { returnType: 'string', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ @@ -4798,7 +4798,7 @@ const caseDefinition: FunctionDefinition = { returnType: 'any', }, ], - supportedCommands: ['stats', 'eval', 'where', 'row', 'sort'], + supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, examples: [ diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts index 201b7bf045d0f2..b7ef6e0ba9e880 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts @@ -571,3 +571,6 @@ export function shouldBeQuotedText( ) { return dashSupported ? /[^a-zA-Z\d_\.@-]/.test(text) : /[^a-zA-Z\d_\.@]/.test(text); } + +export const isAggFunction = (arg: ESQLFunction): boolean => + getFunctionDefinition(arg.name)?.type === 'agg'; diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/variables.ts b/packages/kbn-esql-validation-autocomplete/src/shared/variables.ts index 9debf8a67083f2..22c38cd286e191 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/variables.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/variables.ts @@ -134,6 +134,21 @@ function addVariableFromExpression( } } +export const collectVariablesFromList = ( + list: ESQLAstItem[], + fields: Map, + queryString: string, + variables: Map +) => { + for (const arg of list) { + if (isAssignment(arg)) { + addVariableFromAssignment(arg, variables, fields); + } else if (isExpression(arg)) { + addVariableFromExpression(arg, queryString, variables); + } + } +}; + export function collectVariables( commands: ESQLCommand[], fields: Map, @@ -141,28 +156,14 @@ export function collectVariables( ): Map { const variables = new Map(); for (const command of commands) { - if (['row', 'eval', 'stats'].includes(command.name)) { - for (const arg of command.args) { - if (isAssignment(arg)) { - addVariableFromAssignment(arg, variables, fields); - } - if (isExpression(arg)) { - addVariableFromExpression(arg, queryString, variables); - } - } + if (['row', 'eval', 'stats', 'metrics'].includes(command.name)) { + collectVariablesFromList(command.args, fields, queryString, variables); if (command.name === 'stats') { const commandOptionsWithAssignment = command.args.filter( (arg) => isOptionItem(arg) && arg.name === 'by' ) as ESQLCommandOption[]; for (const commandOption of commandOptionsWithAssignment) { - for (const optArg of commandOption.args) { - if (isAssignment(optArg)) { - addVariableFromAssignment(optArg, variables, fields); - } - if (isExpression(optArg)) { - addVariableFromExpression(optArg, queryString, variables); - } - } + collectVariablesFromList(commandOption.args, fields, queryString, variables); } } } diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/callbacks.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/callbacks.test.ts new file mode 100644 index 00000000000000..96338afde56a33 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/callbacks.test.ts @@ -0,0 +1,31 @@ +/* + * 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 { setup } from './helpers'; + +describe('FROM', () => { + test('does not load fields when validating only a single FROM, SHOW, ROW command', async () => { + const { validate, callbacks } = await setup(); + + await validate('FROM kib'); + await validate('FROM kibana_ecommerce METADATA _i'); + await validate('FROM kibana_ecommerce METADATA _id | '); + await validate('SHOW'); + await validate('ROW \t'); + + expect(callbacks.getFieldsFor.mock.calls.length).toBe(0); + }); + + test('loads fields with FROM source when commands after pipe present', async () => { + const { validate, callbacks } = await setup(); + + await validate('FROM kibana_ecommerce METADATA _id | eval'); + + expect(callbacks.getFieldsFor.mock.calls.length).toBe(1); + }); +}); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/helpers.ts new file mode 100644 index 00000000000000..9d28f88115b429 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/helpers.ts @@ -0,0 +1,71 @@ +/* + * 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 { EditorError, ESQLMessage, getAstAndSyntaxErrors } from '@kbn/esql-ast'; +import { ESQLCallbacks } from '../../shared/types'; +import { getCallbackMocks } from '../../__tests__/helpers'; +import { ValidationOptions } from '../types'; +import { validateQuery } from '../validation'; + +/** Validation test API factory, can be called at the start of each unit test. */ +export type Setup = typeof setup; + +/** + * Sets up an API for ES|QL query validation testing. + * + * @returns API for testing validation logic. + */ +export const setup = async () => { + const callbacks = getCallbackMocks(); + + const validate = async ( + query: string, + opts: ValidationOptions = {}, + cb: ESQLCallbacks = callbacks + ) => { + return await validateQuery(query, getAstAndSyntaxErrors, opts, cb); + }; + + const assertErrors = (errors: unknown[], expectedErrors: string[]) => { + const errorMessages: string[] = []; + for (const error of errors) { + if (error && typeof error === 'object') { + const message = + typeof (error as ESQLMessage).text === 'string' + ? (error as ESQLMessage).text + : typeof (error as EditorError).message === 'string' + ? (error as EditorError).message + : String(error); + errorMessages.push(message); + } else { + errorMessages.push(String(error)); + } + } + expect(errorMessages.sort()).toStrictEqual(expectedErrors.sort()); + }; + + const expectErrors = async ( + query: string, + expectedErrors: string[], + expectedWarnings?: string[], + opts: ValidationOptions = {}, + cb: ESQLCallbacks = callbacks + ) => { + const { errors, warnings } = await validateQuery(query, getAstAndSyntaxErrors, opts, cb); + assertErrors(errors, expectedErrors); + if (expectedWarnings) { + assertErrors(warnings, expectedWarnings); + } + }; + + return { + callbacks, + validate, + expectErrors, + }; +}; diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.from.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.from.ts new file mode 100644 index 00000000000000..74301ced77e630 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.from.ts @@ -0,0 +1,194 @@ +/* + * 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 { METADATA_FIELDS } from '../../../shared/constants'; +import * as helpers from '../helpers'; + +export const validationFromCommandTestSuite = (setup: helpers.Setup) => { + describe('validation', () => { + describe('command', () => { + describe('FROM [ METADATA ]', () => { + test('errors on invalid command start', async () => { + const { expectErrors } = await setup(); + + await expectErrors('f', [ + "SyntaxError: mismatched input 'f' expecting {'explain', 'from', 'meta', 'metrics', 'row', 'show'}", + ]); + await expectErrors('from ', [ + "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''", + ]); + }); + + describe('... ...', () => { + test('no errors on correct indices usage', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from index', []); + await expectErrors('FROM index', []); + await expectErrors('FrOm index', []); + await expectErrors('from index, other_index', []); + await expectErrors('from index, other_index,.secret_index', []); + await expectErrors('from .secret_index', []); + await expectErrors('from .secret_index', []); + await expectErrors('from .secret_index', []); + await expectErrors('from ind*, other*', []); + await expectErrors('from index*', []); + await expectErrors('FROM *a_i*dex*', []); + await expectErrors('FROM in*ex*', []); + await expectErrors('FROM *n*ex', []); + await expectErrors('FROM *n*ex*', []); + await expectErrors('FROM i*d*x*', []); + await expectErrors('FROM i*d*x', []); + await expectErrors('FROM i***x*', []); + await expectErrors('FROM i****', []); + await expectErrors('FROM i**', []); + await expectErrors('fRoM index**', []); + await expectErrors('fRoM *ex', []); + await expectErrors('fRoM *ex*', []); + await expectErrors('fRoM in*ex', []); + await expectErrors('fRoM ind*ex', []); + await expectErrors('fRoM *,-.*', []); + await expectErrors('fRoM remote-*:indexes*', []); + await expectErrors('fRoM remote-*:indexes', []); + await expectErrors('fRoM remote-ccs:indexes', []); + await expectErrors('fRoM a_index, remote-ccs:indexes', []); + await expectErrors('fRoM .secret_index', []); + await expectErrors('from my-index', []); + }); + + test('errors on trailing comma', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from index,', [ + "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''", + ]); + await expectErrors(`FROM index\n, \tother_index\t,\n \t `, [ + "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''", + ]); + + await expectErrors(`from assignment = 1`, [ + "SyntaxError: mismatched input '=' expecting ", + 'Unknown index [assignment]', + ]); + }); + + test('errors on invalid syntax', async () => { + const { expectErrors } = await setup(); + + await expectErrors('FROM `index`', [ + "SyntaxError: token recognition error at: '`'", + "SyntaxError: token recognition error at: '`'", + ]); + await expectErrors(`from assignment = 1`, [ + "SyntaxError: mismatched input '=' expecting ", + 'Unknown index [assignment]', + ]); + }); + + test('errors on unknown index', async () => { + const { expectErrors } = await setup(); + + await expectErrors(`FROM index, missingIndex`, ['Unknown index [missingIndex]']); + await expectErrors(`from average()`, ['Unknown index [average()]']); + await expectErrors(`fRom custom_function()`, ['Unknown index [custom_function()]']); + await expectErrors(`FROM indexes*`, ['Unknown index [indexes*]']); + await expectErrors('from numberField', ['Unknown index [numberField]']); + await expectErrors('FROM policy', ['Unknown index [policy]']); + }); + }); + + describe('... METADATA ', () => { + test('no errors on correct METADATA ... usage', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from index metadata _id', []); + await expectErrors('from index metadata _id, \t\n _index\n ', []); + }); + + test('errors when wrapped in brackets', async () => { + const { expectErrors } = await setup(); + + await expectErrors(`from index (metadata _id)`, [ + "SyntaxError: mismatched input '(metadata' expecting ", + ]); + }); + + for (const isWrapped of [true, false]) { + function setWrapping(option: string) { + return isWrapped ? `[${option}]` : option; + } + + function addBracketsWarning() { + return isWrapped + ? ["Square brackets '[]' need to be removed from FROM METADATA declaration"] + : []; + } + + describe(`wrapped = ${isWrapped}`, () => { + test('no errors on correct usage, waning on square brackets', async () => { + const { expectErrors } = await setup(); + + await expectErrors(`from index ${setWrapping('METADATA _id')}`, []); + await expectErrors( + `from index ${setWrapping('METADATA _id')}`, + [], + addBracketsWarning() + ); + await expectErrors( + `from index ${setWrapping('metadata _id')}`, + [], + addBracketsWarning() + ); + await expectErrors( + `from index ${setWrapping('METADATA _id, _source')}`, + [], + addBracketsWarning() + ); + await expectErrors( + `from remote-ccs:indexes ${setWrapping('METADATA _id')}`, + [], + addBracketsWarning() + ); + await expectErrors( + `from *:indexes ${setWrapping('METADATA _id')}`, + [], + addBracketsWarning() + ); + }); + + test('validates fields', async () => { + const { expectErrors } = await setup(); + + await expectErrors( + `from index ${setWrapping('METADATA _id, _source2')}`, + [ + `Metadata field [_source2] is not available. Available metadata fields are: [${METADATA_FIELDS.join( + ', ' + )}]`, + ], + addBracketsWarning() + ); + await expectErrors( + `from index ${setWrapping('metadata _id, _source')} ${setWrapping( + 'METADATA _id2' + )}`, + [ + isWrapped + ? "SyntaxError: mismatched input '[' expecting " + : "SyntaxError: mismatched input 'METADATA' expecting ", + ], + addBracketsWarning() + ); + }); + }); + } + }); + }); + }); + }); +}; diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.metrics.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.metrics.ts new file mode 100644 index 00000000000000..5d1ddb0865ea53 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.metrics.ts @@ -0,0 +1,293 @@ +/* + * 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 * as helpers from '../helpers'; + +export const validationMetricsCommandTestSuite = (setup: helpers.Setup) => { + describe('validation', () => { + describe('command', () => { + describe('METRICS [ [ BY ]]', () => { + test('errors on invalid command start', async () => { + const { expectErrors } = await setup(); + + await expectErrors('m', [ + "SyntaxError: mismatched input 'm' expecting {'explain', 'from', 'meta', 'metrics', 'row', 'show'}", + ]); + await expectErrors('metrics ', [ + "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''", + ]); + }); + + describe('... ...', () => { + test('no errors on correct indices usage', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics index', []); + await expectErrors('metrics index, other_index', []); + await expectErrors('metrics index, other_index,.secret_index', []); + await expectErrors('metrics .secret_index', []); + await expectErrors('METRICS .secret_index', []); + await expectErrors('mEtRiCs .secret_index', []); + await expectErrors('metrics ind*, other*', []); + await expectErrors('metrics index*', []); + await expectErrors('metrics *a_i*dex*', []); + await expectErrors('metrics in*ex*', []); + await expectErrors('metrics *n*ex', []); + await expectErrors('metrics *n*ex*', []); + await expectErrors('metrics i*d*x*', []); + await expectErrors('metrics i*d*x', []); + await expectErrors('metrics i***x*', []); + await expectErrors('metrics i****', []); + await expectErrors('metrics i**', []); + await expectErrors('metrics index**', []); + await expectErrors('metrics *ex', []); + await expectErrors('metrics *ex*', []); + await expectErrors('metrics in*ex', []); + await expectErrors('metrics ind*ex', []); + await expectErrors('metrics *,-.*', []); + await expectErrors('metrics remote-*:indexes*', []); + await expectErrors('metrics remote-*:indexes', []); + await expectErrors('metrics remote-ccs:indexes', []); + await expectErrors('metrics a_index, remote-ccs:indexes', []); + await expectErrors('metrics .secret_index', []); + }); + + test('errors on trailing comma', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics index,', [ + "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''", + ]); + await expectErrors(`metrics index\n, \tother_index\t,\n \t `, [ + "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''", + ]); + }); + + test('errors on invalid syntax', async () => { + const { expectErrors } = await setup(); + + await expectErrors(`metrics index = 1`, [ + "SyntaxError: token recognition error at: '='", + "SyntaxError: token recognition error at: '1'", + ]); + await expectErrors('metrics `index`', [ + "SyntaxError: token recognition error at: '`'", + "SyntaxError: token recognition error at: '`'", + ]); + }); + + test('errors on unknown index', async () => { + const { expectErrors } = await setup(); + + await expectErrors(`METRICS index, missingIndex`, ['Unknown index [missingIndex]']); + await expectErrors(`METRICS average()`, ['Unknown index [average()]']); + await expectErrors(`metrics custom_function()`, ['Unknown index [custom_function()]']); + await expectErrors(`metrics indexes*`, ['Unknown index [indexes*]']); + await expectErrors('metrics numberField', ['Unknown index [numberField]']); + await expectErrors('metrics policy', ['Unknown index [policy]']); + }); + }); + + describe('... ...', () => { + test('no errors on correct usage', async () => { + const { expectErrors } = await setup(); + + await expectErrors('METRICS a_index count()', []); + await expectErrors('metrics a_index avg(numberField) by 1', []); + await expectErrors('metrics a_index count(`numberField`)', []); + await expectErrors('metrics a_index count(*)', []); + await expectErrors('metrics index var0 = count(*)', []); + await expectErrors('metrics a_index var0 = count()', []); + await expectErrors('metrics a_index var0 = avg(numberField), count(*)', []); + await expectErrors(`metrics a_index sum(case(false, 0, 1))`, []); + await expectErrors(`metrics a_index var0 = sum( case(false, 0, 1))`, []); + await expectErrors('metrics a_index count(stringField == "a" or null)', []); + await expectErrors('metrics other_index max(numberField) by stringField', []); + }); + + test('syntax errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics a_index numberField=', [ + expect.any(String), + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + ]); + await expectErrors('metrics a_index numberField=5 by ', [ + expect.any(String), + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + ]); + }); + + test('errors on unknown function', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics a_index var0 = avg(fn(number)), count(*)', [ + 'Unknown function [fn]', + ]); + }); + + test('errors when no aggregation function specified', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics a_index numberField + 1', [ + 'At least one aggregation function required in [METRICS], found [numberField+1]', + ]); + await expectErrors('metrics a_index a = numberField + 1', [ + 'At least one aggregation function required in [METRICS], found [a=numberField+1]', + ]); + await expectErrors('metrics a_index a = numberField + 1, stringField', [ + 'At least one aggregation function required in [METRICS], found [a=numberField+1]', + 'Expected an aggregate function or group but got [stringField] of type [FieldAttribute]', + ]); + await expectErrors('metrics a_index numberField + 1 by ipField', [ + 'At least one aggregation function required in [METRICS], found [numberField+1]', + ]); + }); + + test('errors on agg and non-agg mix', async () => { + const { expectErrors } = await setup(); + + await expectErrors('METRICS a_index sum( numberField ) + abs( numberField ) ', [ + 'Cannot combine aggregation and non-aggregation values in [METRICS], found [sum(numberField)+abs(numberField)]', + ]); + await expectErrors('METRICS a_index abs( numberField + sum( numberField )) ', [ + 'Cannot combine aggregation and non-aggregation values in [METRICS], found [abs(numberField+sum(numberField))]', + ]); + }); + + test('errors when aggregation functions are nested', async () => { + const { expectErrors } = await setup(); + + // avg() inside avg() + await expectErrors('METRICS a_index avg(to_long(avg(2)))', [ + 'The aggregation function [avg] cannot be used as an argument in another aggregation function', + ]); + }); + + test('errors when input is not an aggregate function', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics a_index numberField ', [ + 'Expected an aggregate function or group but got [numberField] of type [FieldAttribute]', + ]); + }); + + test('sub-command can reference aggregated field', async () => { + const { expectErrors } = await setup(); + + for (const subCommand of ['keep', 'drop', 'eval']) { + await expectErrors( + 'metrics a_index count(`numberField`) | ' + + subCommand + + ' `count(``numberField``)` ', + [] + ); + } + }); + + test('semantic function validation errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics a_index count(round(*))', [ + 'Using wildcards (*) in round is not allowed', + ]); + await expectErrors('metrics a_index count(count(*))', [ + `Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [count(*)] of type [number]`, + ]); + }); + }); + + describe('... BY ', () => { + test('no errors on correct usage', async () => { + const { expectErrors } = await setup(); + + await expectErrors( + 'metrics a_index avg(numberField), percentile(numberField, 50) by ipField', + [] + ); + await expectErrors( + 'metrics a_index avg(numberField), percentile(numberField, 50) BY ipField', + [] + ); + await expectErrors( + 'metrics a_index avg(numberField), percentile(numberField, 50) + 1 by ipField', + [] + ); + await expectErrors('metrics a_index avg(numberField) by stringField | limit 100', []); + for (const op of ['+', '-', '*', '/', '%']) { + await expectErrors( + `metrics a_index avg(numberField) ${op} percentile(numberField, 50) BY ipField`, + [] + ); + } + }); + + test('syntax does not allow clause without ', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics a_index BY stringField', [ + 'Expected an aggregate function or group but got [BY] of type [FieldAttribute]', + "SyntaxError: extraneous input 'stringField' expecting ", + ]); + }); + + test('syntax errors in ', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics a_index count(* + 1) BY ipField', [ + "SyntaxError: no viable alternative at input 'count(* +'", + ]); + await expectErrors('metrics a_index \n count(* + round(numberField)) BY ipField', [ + "SyntaxError: no viable alternative at input 'count(* +'", + ]); + }); + + test('semantic errors in ', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics a_index count(round(*)) BY ipField', [ + 'Using wildcards (*) in round is not allowed', + ]); + await expectErrors('metrics a_index count(count(*)) BY ipField', [ + `Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [count(*)] of type [number]`, + ]); + }); + + test('errors on unknown field', async () => { + const { expectErrors } = await setup(); + + await expectErrors('metrics a_index avg(numberField) by wrongField', [ + 'Unknown column [wrongField]', + ]); + await expectErrors('metrics a_index avg(numberField) by wrongField + 1', [ + 'Unknown column [wrongField]', + ]); + await expectErrors('metrics a_index avg(numberField) by var0 = wrongField + 1', [ + 'Unknown column [wrongField]', + ]); + }); + + test('various errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors('METRICS a_index avg(numberField) by percentile(numberField)', [ + 'METRICS BY does not support function percentile', + ]); + await expectErrors( + 'METRICS a_index avg(numberField) by stringField, percentile(numberField) by ipField', + [ + "SyntaxError: mismatched input 'by' expecting ", + 'METRICS BY does not support function percentile', + ] + ); + }); + }); + }); + }); + }); +}; diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts new file mode 100644 index 00000000000000..5a98d362dc002a --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts @@ -0,0 +1,365 @@ +/* + * 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 * as helpers from '../helpers'; + +export const validationStatsCommandTestSuite = (setup: helpers.Setup) => { + describe('validation', () => { + describe('command', () => { + describe('STATS [ BY ]', () => { + test('no errors on correct usage', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats by stringField', []); + await expectErrors( + `FROM index + | EVAL numberField * 3.281 + | STATS avg_numberField = AVG(\`numberField * 3.281\`)`, + [] + ); + await expectErrors( + `FROM index | STATS AVG(numberField) by round(numberField) + 1 | EVAL \`round(numberField) + 1\` / 2`, + [] + ); + }); + + test('errors on invalid command start', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats ', [ + 'At least one aggregation or grouping expression required in [STATS]', + ]); + }); + + describe('... ...', () => { + test('no errors on correct usage', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats avg(numberField) by 1', []); + await expectErrors('from a_index | stats count(`numberField`)', []); + await expectErrors('from a_index | stats count(*)', []); + await expectErrors('from a_index | stats count()', []); + await expectErrors('from a_index | stats var0 = count(*)', []); + await expectErrors('from a_index | stats var0 = count()', []); + await expectErrors('from a_index | stats var0 = avg(numberField), count(*)', []); + await expectErrors(`from a_index | stats sum(case(false, 0, 1))`, []); + await expectErrors(`from a_index | stats var0 = sum( case(false, 0, 1))`, []); + + // "or" must accept "null" + await expectErrors('from a_index | stats count(stringField == "a" or null)', []); + }); + + test('sub-command can reference aggregated field', async () => { + const { expectErrors } = await setup(); + + for (const subCommand of ['keep', 'drop', 'eval']) { + await expectErrors( + 'from a_index | stats count(`numberField`) | ' + + subCommand + + ' `count(``numberField``)` ', + [] + ); + } + }); + + test('errors on agg and non-agg mix', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | STATS sum( numberField ) + abs( numberField ) ', [ + 'Cannot combine aggregation and non-aggregation values in [STATS], found [sum(numberField)+abs(numberField)]', + ]); + await expectErrors('from a_index | STATS abs( numberField + sum( numberField )) ', [ + 'Cannot combine aggregation and non-aggregation values in [STATS], found [abs(numberField+sum(numberField))]', + ]); + }); + + test('errors on each aggregation field, which does not contain at least one agg function', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats numberField + 1', [ + 'At least one aggregation function required in [STATS], found [numberField+1]', + ]); + await expectErrors('from a_index | stats numberField + 1, stringField', [ + 'At least one aggregation function required in [STATS], found [numberField+1]', + 'Expected an aggregate function or group but got [stringField] of type [FieldAttribute]', + ]); + await expectErrors('from a_index | stats numberField + 1, numberField + 2, count()', [ + 'At least one aggregation function required in [STATS], found [numberField+1]', + 'At least one aggregation function required in [STATS], found [numberField+2]', + ]); + await expectErrors( + 'from a_index | stats numberField + 1, numberField + count(), count()', + ['At least one aggregation function required in [STATS], found [numberField+1]'] + ); + await expectErrors('from a_index | stats 5 + numberField + 1', [ + 'At least one aggregation function required in [STATS], found [5+numberField+1]', + ]); + await expectErrors('from a_index | stats numberField + 1 by ipField', [ + 'At least one aggregation function required in [STATS], found [numberField+1]', + ]); + }); + + test('errors when input is not an aggregate function', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats numberField ', [ + 'Expected an aggregate function or group but got [numberField] of type [FieldAttribute]', + ]); + }); + + test('various errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats numberField=', [ + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + ]); + await expectErrors('from a_index | stats numberField=5 by ', [ + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + ]); + await expectErrors('from a_index | stats avg(numberField) by wrongField', [ + 'Unknown column [wrongField]', + ]); + await expectErrors('from a_index | stats avg(numberField) by wrongField + 1', [ + 'Unknown column [wrongField]', + ]); + await expectErrors('from a_index | stats avg(numberField) by var0 = wrongField + 1', [ + 'Unknown column [wrongField]', + ]); + await expectErrors('from a_index | stats var0 = avg(fn(number)), count(*)', [ + 'Unknown function [fn]', + ]); + }); + + test('semantic errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats count(round(*))', [ + 'Using wildcards (*) in round is not allowed', + ]); + await expectErrors('from a_index | stats count(count(*))', [ + `Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [count(*)] of type [number]`, + ]); + }); + }); + + describe('... BY ', () => { + test('no errors on correct usage', async () => { + const { expectErrors } = await setup(); + + await expectErrors( + 'from a_index | stats avg(numberField), percentile(numberField, 50) by ipField', + [] + ); + await expectErrors( + 'from a_index | stats avg(numberField), percentile(numberField, 50) BY ipField', + [] + ); + await expectErrors( + 'from a_index | stats avg(numberField), percentile(numberField, 50) + 1 by ipField', + [] + ); + for (const op of ['+', '-', '*', '/', '%']) { + await expectErrors( + `from a_index | stats avg(numberField) ${op} percentile(numberField, 50) BY ipField`, + [] + ); + } + }); + + test('cannot specify without ', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats by ', [ + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + ]); + }); + + test('syntax errors in ', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats count(* + 1) BY ipField', [ + "SyntaxError: no viable alternative at input 'count(* +'", + ]); + await expectErrors('from a_index | stats count(* + round(numberField)) BY ipField', [ + "SyntaxError: no viable alternative at input 'count(* +'", + ]); + }); + + test('semantic errors in ', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats count(round(*)) BY ipField', [ + 'Using wildcards (*) in round is not allowed', + ]); + await expectErrors('from a_index | stats count(count(*)) BY ipField', [ + `Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [count(*)] of type [number]`, + ]); + }); + + test('various errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from a_index | stats avg(numberField) by percentile(numberField)', [ + 'STATS BY does not support function percentile', + ]); + await expectErrors( + 'from a_index | stats avg(numberField) by stringField, percentile(numberField) by ipField', + [ + "SyntaxError: mismatched input 'by' expecting ", + 'STATS BY does not support function percentile', + ] + ); + }); + + describe('constant-only parameters', () => { + test('no errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors('from index | stats by bucket(dateField, pi(), "", "")', []); + await expectErrors( + 'from index | stats by bucket(dateField, 1 + 30 / 10, "", "")', + [] + ); + await expectErrors( + 'from index | stats by bucket(dateField, 1 + 30 / 10, concat("", ""), "")', + [] + ); + }); + + test('errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors( + 'from index | stats by bucket(dateField, abs(numberField), "", "")', + ['Argument of [bucket] must be a constant, received [abs(numberField)]'] + ); + await expectErrors( + 'from index | stats by bucket(dateField, abs(length(numberField)), "", "")', + ['Argument of [bucket] must be a constant, received [abs(length(numberField))]'] + ); + await expectErrors( + 'from index | stats by bucket(dateField, numberField, stringField, stringField)', + [ + 'Argument of [bucket] must be a constant, received [numberField]', + 'Argument of [bucket] must be a constant, received [stringField]', + 'Argument of [bucket] must be a constant, received [stringField]', + ] + ); + }); + }); + }); + + describe('nesting', () => { + const NESTING_LEVELS = 4; + const NESTED_DEPTHS = Array(NESTING_LEVELS) + .fill(0) + .map((_, i) => i + 1); + + for (const nesting of NESTED_DEPTHS) { + describe(`depth = ${nesting}`, () => { + describe('builtin', () => { + const builtinWrapping = Array(nesting).fill('+1').join(''); + + test('no errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors( + `from a_index | stats 5 + avg(numberField) ${builtinWrapping}`, + [] + ); + await expectErrors( + `from a_index | stats 5 ${builtinWrapping} + avg(numberField)`, + [] + ); + }); + + test('errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors(`from a_index | stats 5 ${builtinWrapping} + numberField`, [ + `At least one aggregation function required in [STATS], found [5${builtinWrapping}+numberField]`, + ]); + await expectErrors(`from a_index | stats 5 + numberField ${builtinWrapping}`, [ + `At least one aggregation function required in [STATS], found [5+numberField${builtinWrapping}]`, + ]); + await expectErrors( + `from a_index | stats 5 + numberField ${builtinWrapping}, var0 = sum(numberField)`, + [ + `At least one aggregation function required in [STATS], found [5+numberField${builtinWrapping}]`, + ] + ); + }); + }); + + describe('EVAL', () => { + const evalWrapping = Array(nesting).fill('round(').join(''); + const closingWrapping = Array(nesting).fill(')').join(''); + + test('no errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors( + `from a_index | stats ${evalWrapping} sum(numberField) ${closingWrapping}`, + [] + ); + await expectErrors( + `from a_index | stats ${evalWrapping} sum(numberField) ${closingWrapping} + ${evalWrapping} sum(numberField) ${closingWrapping}`, + [] + ); + await expectErrors( + `from a_index | stats ${evalWrapping} sum(numberField + numberField) ${closingWrapping}`, + [] + ); + await expectErrors( + `from a_index | stats ${evalWrapping} sum(numberField + round(numberField)) ${closingWrapping}`, + [] + ); + await expectErrors( + `from a_index | stats ${evalWrapping} sum(numberField + round(numberField)) ${closingWrapping} + ${evalWrapping} sum(numberField + round(numberField)) ${closingWrapping}`, + [] + ); + await expectErrors( + `from a_index | stats sum(${evalWrapping} numberField ${closingWrapping} )`, + [] + ); + await expectErrors( + `from a_index | stats sum(${evalWrapping} numberField ${closingWrapping} ) + sum(${evalWrapping} numberField ${closingWrapping} )`, + [] + ); + }); + + test('errors', async () => { + const { expectErrors } = await setup(); + + await expectErrors( + `from a_index | stats ${evalWrapping} numberField + sum(numberField) ${closingWrapping}`, + [ + `Cannot combine aggregation and non-aggregation values in [STATS], found [${evalWrapping}numberField+sum(numberField)${closingWrapping}]`, + ] + ); + await expectErrors( + `from a_index | stats ${evalWrapping} numberField + sum(numberField) ${closingWrapping}, var0 = sum(numberField)`, + [ + `Cannot combine aggregation and non-aggregation values in [STATS], found [${evalWrapping}numberField+sum(numberField)${closingWrapping}]`, + ] + ); + await expectErrors( + `from a_index | stats var0 = ${evalWrapping} numberField + sum(numberField) ${closingWrapping}, var1 = sum(numberField)`, + [ + `Cannot combine aggregation and non-aggregation values in [STATS], found [${evalWrapping}numberField+sum(numberField)${closingWrapping}]`, + ] + ); + }); + }); + }); + } + }); + }); + }); + }); +}; diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/types.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/types.ts new file mode 100644 index 00000000000000..fa1bf59bcb1f7c --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/types.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 interface ValidationTestCase { + query: string; + error: string[]; + warning: string[]; +} + +export interface ValidationTestSuite { + testCases: ValidationTestCase[]; +} diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.from.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.from.test.ts new file mode 100644 index 00000000000000..9182bd2fac0dda --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.from.test.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. + */ + +import * as helpers from './helpers'; +import { validationFromCommandTestSuite } from './test_suites/validation.command.from'; + +validationFromCommandTestSuite(helpers.setup); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.metrics.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.metrics.test.ts new file mode 100644 index 00000000000000..24430e52c07547 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.metrics.test.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. + */ + +import * as helpers from './helpers'; +import { validationMetricsCommandTestSuite } from './test_suites/validation.command.metrics'; + +validationMetricsCommandTestSuite(helpers.setup); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.stats.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.stats.test.ts new file mode 100644 index 00000000000000..cc4a33cb72b88e --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.command.stats.test.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. + */ + +import * as helpers from './helpers'; +import { validationStatsCommandTestSuite } from './test_suites/validation.command.stats'; + +validationStatsCommandTestSuite(helpers.setup); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/errors.ts b/packages/kbn-esql-validation-autocomplete/src/validation/errors.ts index 705df80996a348..b351a495e73c1f 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/errors.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/errors.ts @@ -7,7 +7,13 @@ */ import { i18n } from '@kbn/i18n'; -import type { ESQLLocation, ESQLMessage } from '@kbn/esql-ast'; +import type { + ESQLColumn, + ESQLCommand, + ESQLFunction, + ESQLLocation, + ESQLMessage, +} from '@kbn/esql-ast'; import type { ErrorTypes, ErrorValues } from './types'; function getMessageAndTypeFromId({ @@ -370,6 +376,46 @@ function getMessageAndTypeFromId({ ), type: 'error', }; + case 'noAggFunction': + return { + message: i18n.translate('kbn-esql-validation-autocomplete.esql.validation.noAggFunction', { + defaultMessage: + 'At least one aggregation function required in [{command}], found [{expression}]', + values: { + command: out.commandName.toUpperCase(), + expression: out.expression, + }, + }), + type: 'error', + }; + case 'expressionNotAggClosed': + return { + message: i18n.translate( + 'kbn-esql-validation-autocomplete.esql.validation.expressionNotAggClosed', + { + defaultMessage: + 'Cannot combine aggregation and non-aggregation values in [{command}], found [{expression}]', + values: { + command: out.commandName.toUpperCase(), + expression: out.expression, + }, + } + ), + type: 'error', + }; + case 'aggInAggFunction': + return { + message: i18n.translate( + 'kbn-esql-validation-autocomplete.esql.validation.aggInAggFunction', + { + defaultMessage: + 'The aggregation function [{nestedAgg}] cannot be used as an argument in another aggregation function', + values: { + nestedAgg: out.nestedAgg, + }, + } + ), + }; } return { message: '' }; } @@ -391,7 +437,7 @@ export function createMessage( message: string, location: ESQLLocation, messageId: string -) { +): ESQLMessage { return { type, text: message, @@ -400,6 +446,65 @@ export function createMessage( }; } +const createError = (messageId: string, location: ESQLLocation, message: string = '') => + createMessage('error', message, location, messageId); + +export const errors = { + unexpected: ( + location: ESQLLocation, + message: string = i18n.translate( + 'kbn-esql-validation-autocomplete.esql.validation.errors.unexpected.message', + { + defaultMessage: 'Unexpected error, this should never happen.', + } + ) + ): ESQLMessage => { + return createError('unexpected', location, message); + }, + + byId: ( + id: K, + location: ESQLLocation, + values: ErrorValues + ): ESQLMessage => + getMessageFromId({ + messageId: id, + values, + locations: location, + }), + + unknownFunction: (fn: ESQLFunction): ESQLMessage => + errors.byId('unknownFunction', fn.location, fn), + + unknownColumn: (column: ESQLColumn): ESQLMessage => + errors.byId('unknownColumn', column.location, { + name: column.name, + }), + + noAggFunction: (cmd: ESQLCommand, fn: ESQLFunction): ESQLMessage => + errors.byId('noAggFunction', fn.location, { + commandName: cmd.name, + expression: fn.text, + }), + + expressionNotAggClosed: (cmd: ESQLCommand, fn: ESQLFunction): ESQLMessage => + errors.byId('expressionNotAggClosed', fn.location, { + commandName: cmd.name, + expression: fn.text, + }), + + unknownAggFunction: (col: ESQLColumn, type: string = 'FieldAttribute'): ESQLMessage => + errors.byId('unknownAggregateFunction', col.location, { + value: col.name, + type, + }), + + aggInAggFunction: (fn: ESQLFunction): ESQLMessage => + errors.byId('aggInAggFunction', fn.location, { + nestedAgg: fn.name, + }), +}; + export function getUnknownTypeLabel() { return i18n.translate('kbn-esql-validation-autocomplete.esql.validation.unknownColumnType', { defaultMessage: 'Unknown type', diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json index ba80daea19780c..9b03737786c12c 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json +++ b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json @@ -189,8233 +189,7273 @@ "warning": [] }, { - "query": "f", + "query": "row", "error": [ - "SyntaxError: mismatched input 'f' expecting {'explain', 'from', 'meta', 'metrics', 'row', 'show'}" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, { - "query": "from ", + "query": "row missing_column", "error": [ - "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''" + "Unknown column [missing_column]" ], "warning": [] }, { - "query": "from index,", + "query": "row fn()", "error": [ - "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''" + "Unknown function [fn]" ], "warning": [] }, { - "query": "from assignment = 1", + "query": "row missing_column, missing_column2", "error": [ - "SyntaxError: mismatched input '=' expecting ", - "Unknown index [assignment]" + "Unknown column [missing_column]", + "Unknown column [missing_column2]" ], "warning": [] }, { - "query": "from index", - "error": [], - "warning": [] - }, - { - "query": "FROM index", - "error": [], - "warning": [] - }, - { - "query": "FrOm index", + "query": "row a=1", "error": [], "warning": [] }, { - "query": "from `index`", + "query": "row a=1, missing_column", "error": [ - "SyntaxError: token recognition error at: '`'", - "SyntaxError: token recognition error at: '`'" + "Unknown column [missing_column]" ], "warning": [] }, { - "query": "from index, other_index", - "error": [], - "warning": [] - }, - { - "query": "from index, missingIndex", + "query": "row a=1, b = average()", "error": [ - "Unknown index [missingIndex]" + "Unknown function [average]" ], "warning": [] }, { - "query": "from fn()", - "error": [ - "Unknown index [fn()]" - ], + "query": "row a = [1, 2, 3]", + "error": [], "warning": [] }, { - "query": "from average()", - "error": [ - "Unknown index [average()]" - ], + "query": "row a = [true, false]", + "error": [], "warning": [] }, { - "query": "from index [METADATA _id]", + "query": "row a = [\"a\", \"b\"]", "error": [], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] + "warning": [] }, { - "query": "from index [metadata _id]", + "query": "row a = null", "error": [], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] + "warning": [] }, { - "query": "from index [METADATA _id, _source]", + "query": "row a = (1)", "error": [], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] - }, - { - "query": "from index [METADATA _id, _source2]", - "error": [ - "Metadata field [_source2] is not available. Available metadata fields are: [_version, _id, _index, _source, _ignored]" - ], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] + "warning": [] }, { - "query": "from index [metadata _id, _source] [METADATA _id2]", + "query": "row a = (1, 2, 3)", "error": [ - "SyntaxError: mismatched input '[' expecting " + "SyntaxError: no viable alternative at input '(1,'", + "SyntaxError: extraneous input ')' expecting " ], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] + "warning": [] }, { - "query": "from remote-ccs:indexes [METADATA _id]", + "query": "row a=NOT true", "error": [], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] + "warning": [] }, { - "query": "from *:indexes [METADATA _id]", + "query": "row NOT true", "error": [], - "warning": [ - "Square brackets '[]' need to be removed from FROM METADATA declaration" - ] + "warning": [] }, { - "query": "from index METADATA _id", + "query": "row a=NOT false", "error": [], "warning": [] }, { - "query": "from index metadata _id", + "query": "row NOT false", "error": [], "warning": [] }, { - "query": "from index METADATA _id, _source", - "error": [], + "query": "row var = 1 in ", + "error": [ + "SyntaxError: mismatched input '' expecting '('" + ], "warning": [] }, { - "query": "from index METADATA _id, _source2", + "query": "row var = 1 in (", "error": [ - "Metadata field [_source2] is not available. Available metadata fields are: [_version, _id, _index, _source, _ignored]" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "Error: [in] function expects exactly 2 arguments, got 1." ], "warning": [] }, { - "query": "from index metadata _id, _source METADATA _id2", + "query": "row var = 1 not in ", "error": [ - "SyntaxError: mismatched input 'METADATA' expecting " + "SyntaxError: mismatched input '' expecting '('" ], "warning": [] }, { - "query": "from remote-ccs:indexes METADATA _id", + "query": "row var = 1 in (1, 2, 3)", "error": [], "warning": [] }, { - "query": "from *:indexes METADATA _id", + "query": "row var = 5 in (1, 2, 3)", "error": [], "warning": [] }, { - "query": "from index (metadata _id)", - "error": [ - "SyntaxError: mismatched input '(metadata' expecting " - ], + "query": "row var = 5 not in (1, 2, 3)", + "error": [], "warning": [] }, { - "query": "from ind*, other*", + "query": "row var = 1 in (1, 2, 3, round(5))", "error": [], "warning": [] }, { - "query": "from index*", + "query": "row var = \"a\" in (\"a\", \"b\", \"c\")", + "error": [], + "warning": [] + }, + { + "query": "row var = \"a\" in (\"a\", \"b\", \"c\")", "error": [], "warning": [] }, { - "query": "from *a_i*dex*", + "query": "row var = \"a\" not in (\"a\", \"b\", \"c\")", "error": [], "warning": [] }, { - "query": "from in*ex*", + "query": "row var = 1 in (\"a\", \"b\", \"c\")", "error": [], "warning": [] }, { - "query": "from *n*ex", + "query": "row var = 5 in (\"a\", \"b\", \"c\")", "error": [], "warning": [] }, { - "query": "from *n*ex*", + "query": "row var = 5 not in (\"a\", \"b\", \"c\")", "error": [], "warning": [] }, { - "query": "from i*d*x*", + "query": "row var = 5 not in (1, 2, 3, \"a\")", "error": [], "warning": [] }, { - "query": "from i*d*x", + "query": "row bool_var = true and false", "error": [], "warning": [] }, { - "query": "from i***x*", + "query": "row bool_var = true and null", "error": [], "warning": [] }, { - "query": "from i****", + "query": "row bool_var = null and false", "error": [], "warning": [] }, { - "query": "from i**", + "query": "row bool_var = null and null", "error": [], "warning": [] }, { - "query": "from index**", + "query": "row bool_var = true or false", "error": [], "warning": [] }, { - "query": "from *ex", + "query": "row bool_var = true or null", "error": [], "warning": [] }, { - "query": "from *ex*", + "query": "row bool_var = null or false", "error": [], "warning": [] }, { - "query": "from in*ex", + "query": "row bool_var = null or null", "error": [], "warning": [] }, { - "query": "from ind*ex", + "query": "row var = 5 > 0", "error": [], "warning": [] }, { - "query": "from *,-.*", + "query": "row var = NOT 5 > 0", "error": [], "warning": [] }, { - "query": "from indexes*", + "query": "row var = (numberField > 0)", "error": [ - "Unknown index [indexes*]" + "Unknown column [numberField]" ], "warning": [] }, { - "query": "from remote-*:indexes*", + "query": "row var = (NOT (5 > 0))", "error": [], "warning": [] }, { - "query": "from remote-*:indexes", + "query": "row var = to_ip(\"127.0.0.1\") > to_ip(\"127.0.0.1\")", "error": [], "warning": [] }, { - "query": "from remote-ccs:indexes", + "query": "row var = now() > now()", "error": [], "warning": [] }, { - "query": "from a_index, remote-ccs:indexes", + "query": "row var = false > false", + "error": [ + "Argument of [>] must be [number], found value [false] type [boolean]", + "Argument of [>] must be [number], found value [false] type [boolean]" + ], + "warning": [] + }, + { + "query": "row var = now() > \"2022\"", "error": [], "warning": [] }, { - "query": "from .secret_index", + "query": "row var = \"2022\" > now()", "error": [], "warning": [] }, { - "query": "from my-index", + "query": "row var = 5 >= 0", "error": [], "warning": [] }, { - "query": "from numberField", - "error": [ - "Unknown index [numberField]" - ], + "query": "row var = NOT 5 >= 0", + "error": [], "warning": [] }, { - "query": "from policy", + "query": "row var = (numberField >= 0)", "error": [ - "Unknown index [policy]" + "Unknown column [numberField]" ], "warning": [] }, { - "query": "row", - "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], + "query": "row var = (NOT (5 >= 0))", + "error": [], "warning": [] }, { - "query": "row missing_column", - "error": [ - "Unknown column [missing_column]" - ], + "query": "row var = to_ip(\"127.0.0.1\") >= to_ip(\"127.0.0.1\")", + "error": [], "warning": [] }, { - "query": "row fn()", - "error": [ - "Unknown function [fn]" - ], + "query": "row var = now() >= now()", + "error": [], "warning": [] }, { - "query": "row missing_column, missing_column2", + "query": "row var = false >= false", "error": [ - "Unknown column [missing_column]", - "Unknown column [missing_column2]" + "Argument of [>=] must be [number], found value [false] type [boolean]", + "Argument of [>=] must be [number], found value [false] type [boolean]" ], "warning": [] }, { - "query": "row a=1", + "query": "row var = now() >= \"2022\"", "error": [], "warning": [] }, { - "query": "row a=1, missing_column", - "error": [ - "Unknown column [missing_column]" - ], + "query": "row var = \"2022\" >= now()", + "error": [], "warning": [] }, { - "query": "row a=1, b = average()", - "error": [ - "Unknown function [average]" - ], + "query": "row var = 5 < 0", + "error": [], "warning": [] }, { - "query": "row a = [1, 2, 3]", + "query": "row var = NOT 5 < 0", "error": [], "warning": [] }, { - "query": "row a = [true, false]", - "error": [], + "query": "row var = (numberField < 0)", + "error": [ + "Unknown column [numberField]" + ], "warning": [] }, { - "query": "row a = [\"a\", \"b\"]", + "query": "row var = (NOT (5 < 0))", "error": [], "warning": [] }, { - "query": "row a = null", + "query": "row var = to_ip(\"127.0.0.1\") < to_ip(\"127.0.0.1\")", "error": [], "warning": [] }, { - "query": "row a = (1)", + "query": "row var = now() < now()", "error": [], "warning": [] }, { - "query": "row a = (1, 2, 3)", + "query": "row var = false < false", "error": [ - "SyntaxError: no viable alternative at input '(1,'", - "SyntaxError: extraneous input ')' expecting " + "Argument of [<] must be [number], found value [false] type [boolean]", + "Argument of [<] must be [number], found value [false] type [boolean]" ], "warning": [] }, { - "query": "row a=NOT true", + "query": "row var = now() < \"2022\"", "error": [], "warning": [] }, { - "query": "row NOT true", + "query": "row var = \"2022\" < now()", "error": [], "warning": [] }, { - "query": "row a=NOT false", + "query": "row var = 5 <= 0", "error": [], "warning": [] }, { - "query": "row NOT false", + "query": "row var = NOT 5 <= 0", "error": [], "warning": [] }, { - "query": "row var = 1 in ", + "query": "row var = (numberField <= 0)", "error": [ - "SyntaxError: mismatched input '' expecting '('" + "Unknown column [numberField]" ], "warning": [] }, { - "query": "row var = 1 in (", - "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - "Error: [in] function expects exactly 2 arguments, got 1." - ], + "query": "row var = (NOT (5 <= 0))", + "error": [], "warning": [] }, { - "query": "row var = 1 not in ", + "query": "row var = to_ip(\"127.0.0.1\") <= to_ip(\"127.0.0.1\")", + "error": [], + "warning": [] + }, + { + "query": "row var = now() <= now()", + "error": [], + "warning": [] + }, + { + "query": "row var = false <= false", "error": [ - "SyntaxError: mismatched input '' expecting '('" + "Argument of [<=] must be [number], found value [false] type [boolean]", + "Argument of [<=] must be [number], found value [false] type [boolean]" ], "warning": [] }, { - "query": "row var = 1 in (1, 2, 3)", + "query": "row var = now() <= \"2022\"", "error": [], "warning": [] }, { - "query": "row var = 5 in (1, 2, 3)", + "query": "row var = \"2022\" <= now()", "error": [], "warning": [] }, { - "query": "row var = 5 not in (1, 2, 3)", + "query": "row var = 5 == 0", "error": [], "warning": [] }, { - "query": "row var = 1 in (1, 2, 3, round(5))", + "query": "row var = NOT 5 == 0", "error": [], "warning": [] }, { - "query": "row var = \"a\" in (\"a\", \"b\", \"c\")", - "error": [], + "query": "row var = (numberField == 0)", + "error": [ + "Unknown column [numberField]" + ], "warning": [] }, { - "query": "row var = \"a\" in (\"a\", \"b\", \"c\")", + "query": "row var = (NOT (5 == 0))", "error": [], "warning": [] }, { - "query": "row var = \"a\" not in (\"a\", \"b\", \"c\")", + "query": "row var = to_ip(\"127.0.0.1\") == to_ip(\"127.0.0.1\")", "error": [], "warning": [] }, { - "query": "row var = 1 in (\"a\", \"b\", \"c\")", + "query": "row var = now() == now()", "error": [], "warning": [] }, { - "query": "row var = 5 in (\"a\", \"b\", \"c\")", + "query": "row var = false == false", "error": [], "warning": [] }, { - "query": "row var = 5 not in (\"a\", \"b\", \"c\")", + "query": "row var = now() == \"2022\"", "error": [], "warning": [] }, { - "query": "row var = 5 not in (1, 2, 3, \"a\")", + "query": "row var = \"2022\" == now()", "error": [], "warning": [] }, { - "query": "row bool_var = true and false", + "query": "row var = 5 != 0", "error": [], "warning": [] }, { - "query": "row bool_var = true and null", + "query": "row var = NOT 5 != 0", "error": [], "warning": [] }, { - "query": "row bool_var = null and false", - "error": [], + "query": "row var = (numberField != 0)", + "error": [ + "Unknown column [numberField]" + ], "warning": [] }, { - "query": "row bool_var = null and null", + "query": "row var = (NOT (5 != 0))", "error": [], "warning": [] }, { - "query": "row bool_var = true or false", + "query": "row var = to_ip(\"127.0.0.1\") != to_ip(\"127.0.0.1\")", "error": [], "warning": [] }, { - "query": "row bool_var = true or null", + "query": "row var = now() != now()", "error": [], "warning": [] }, { - "query": "row bool_var = null or false", + "query": "row var = false != false", "error": [], "warning": [] }, { - "query": "row bool_var = null or null", + "query": "row var = now() != \"2022\"", "error": [], "warning": [] }, { - "query": "row var = 5 > 0", + "query": "row var = \"2022\" != now()", "error": [], "warning": [] }, { - "query": "row var = NOT 5 > 0", + "query": "row var = 1 + 1", "error": [], "warning": [] }, { - "query": "row var = (numberField > 0)", - "error": [ - "Unknown column [numberField]" - ], + "query": "row var = (5 + 1)", + "error": [], "warning": [] }, { - "query": "row var = (NOT (5 > 0))", - "error": [], + "query": "row var = now() + now()", + "error": [ + "Argument of [+] must be [time_literal], found value [now()] type [date]" + ], "warning": [] }, { - "query": "row var = to_ip(\"127.0.0.1\") > to_ip(\"127.0.0.1\")", + "query": "row var = 1 - 1", "error": [], "warning": [] }, { - "query": "row var = now() > now()", + "query": "row var = (5 - 1)", "error": [], "warning": [] }, { - "query": "row var = false > false", + "query": "row var = now() - now()", "error": [ - "Argument of [>] must be [number], found value [false] type [boolean]", - "Argument of [>] must be [number], found value [false] type [boolean]" + "Argument of [-] must be [time_literal], found value [now()] type [date]" ], "warning": [] }, { - "query": "row var = now() > \"2022\"", + "query": "row var = 1 * 1", "error": [], "warning": [] }, { - "query": "row var = \"2022\" > now()", + "query": "row var = (5 * 1)", "error": [], "warning": [] }, { - "query": "row var = 5 >= 0", - "error": [], + "query": "row var = now() * now()", + "error": [ + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [now()] type [date]" + ], "warning": [] }, { - "query": "row var = NOT 5 >= 0", + "query": "row var = 1 / 1", "error": [], "warning": [] }, { - "query": "row var = (numberField >= 0)", - "error": [ - "Unknown column [numberField]" - ], + "query": "row var = (5 / 1)", + "error": [], "warning": [] }, { - "query": "row var = (NOT (5 >= 0))", - "error": [], + "query": "row var = now() / now()", + "error": [ + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [now()] type [date]" + ], "warning": [] }, { - "query": "row var = to_ip(\"127.0.0.1\") >= to_ip(\"127.0.0.1\")", + "query": "row var = 1 % 1", "error": [], "warning": [] }, { - "query": "row var = now() >= now()", + "query": "row var = (5 % 1)", "error": [], "warning": [] }, { - "query": "row var = false >= false", + "query": "row var = now() % now()", "error": [ - "Argument of [>=] must be [number], found value [false] type [boolean]", - "Argument of [>=] must be [number], found value [false] type [boolean]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [now()] type [date]" ], "warning": [] }, { - "query": "row var = now() >= \"2022\"", + "query": "row var = \"a\" like \"?a\"", "error": [], "warning": [] }, { - "query": "row var = \"2022\" >= now()", + "query": "row var = \"a\" NOT like \"?a\"", "error": [], "warning": [] }, { - "query": "row var = 5 < 0", + "query": "row var = NOT \"a\" like \"?a\"", "error": [], "warning": [] }, { - "query": "row var = NOT 5 < 0", + "query": "row var = NOT \"a\" NOT like \"?a\"", "error": [], "warning": [] }, { - "query": "row var = (numberField < 0)", + "query": "row var = 5 like \"?a\"", "error": [ - "Unknown column [numberField]" + "Argument of [like] must be [string], found value [5] type [number]" ], "warning": [] }, { - "query": "row var = (NOT (5 < 0))", - "error": [], - "warning": [] - }, - { - "query": "row var = to_ip(\"127.0.0.1\") < to_ip(\"127.0.0.1\")", - "error": [], + "query": "row var = 5 NOT like \"?a\"", + "error": [ + "Argument of [not_like] must be [string], found value [5] type [number]" + ], "warning": [] }, { - "query": "row var = now() < now()", - "error": [], + "query": "row var = NOT 5 like \"?a\"", + "error": [ + "Argument of [like] must be [string], found value [5] type [number]" + ], "warning": [] }, { - "query": "row var = false < false", + "query": "row var = NOT 5 NOT like \"?a\"", "error": [ - "Argument of [<] must be [number], found value [false] type [boolean]", - "Argument of [<] must be [number], found value [false] type [boolean]" + "Argument of [not_like] must be [string], found value [5] type [number]" ], "warning": [] }, { - "query": "row var = now() < \"2022\"", + "query": "row var = \"a\" rlike \"?a\"", "error": [], "warning": [] }, { - "query": "row var = \"2022\" < now()", + "query": "row var = \"a\" NOT rlike \"?a\"", "error": [], "warning": [] }, { - "query": "row var = 5 <= 0", + "query": "row var = NOT \"a\" rlike \"?a\"", "error": [], "warning": [] }, { - "query": "row var = NOT 5 <= 0", + "query": "row var = NOT \"a\" NOT rlike \"?a\"", "error": [], "warning": [] }, { - "query": "row var = (numberField <= 0)", + "query": "row var = 5 rlike \"?a\"", "error": [ - "Unknown column [numberField]" + "Argument of [rlike] must be [string], found value [5] type [number]" ], "warning": [] }, { - "query": "row var = (NOT (5 <= 0))", - "error": [], - "warning": [] - }, - { - "query": "row var = to_ip(\"127.0.0.1\") <= to_ip(\"127.0.0.1\")", - "error": [], + "query": "row var = 5 NOT rlike \"?a\"", + "error": [ + "Argument of [not_rlike] must be [string], found value [5] type [number]" + ], "warning": [] }, { - "query": "row var = now() <= now()", - "error": [], + "query": "row var = NOT 5 rlike \"?a\"", + "error": [ + "Argument of [rlike] must be [string], found value [5] type [number]" + ], "warning": [] }, { - "query": "row var = false <= false", + "query": "row var = NOT 5 NOT rlike \"?a\"", "error": [ - "Argument of [<=] must be [number], found value [false] type [boolean]", - "Argument of [<=] must be [number], found value [false] type [boolean]" + "Argument of [not_rlike] must be [string], found value [5] type [number]" ], "warning": [] }, { - "query": "row var = now() <= \"2022\"", + "query": "row var = mv_sort([\"a\", \"b\"], \"bogus\")", "error": [], - "warning": [] + "warning": [ + "Invalid option [\"bogus\"] for mv_sort. Supported options: [\"asc\", \"desc\"]." + ] }, { - "query": "row var = \"2022\" <= now()", + "query": "row var = mv_sort([\"a\", \"b\"], \"ASC\")", "error": [], "warning": [] }, { - "query": "row var = 5 == 0", + "query": "row var = mv_sort([\"a\", \"b\"], \"DESC\")", "error": [], "warning": [] }, { - "query": "row var = NOT 5 == 0", - "error": [], + "query": "row 1 anno", + "error": [ + "ROW does not support [date_period] in expression [1 anno]" + ], "warning": [] }, { - "query": "row var = (numberField == 0)", + "query": "row var = 1 anno", "error": [ - "Unknown column [numberField]" + "Unexpected time interval qualifier: 'anno'" ], "warning": [] }, { - "query": "row var = (NOT (5 == 0))", - "error": [], + "query": "row now() + 1 anno", + "error": [ + "Unexpected time interval qualifier: 'anno'" + ], "warning": [] }, { - "query": "row var = to_ip(\"127.0.0.1\") == to_ip(\"127.0.0.1\")", - "error": [], + "query": "row 1 year", + "error": [ + "ROW does not support [date_period] in expression [1 year]" + ], "warning": [] }, { - "query": "row var = now() == now()", - "error": [], + "query": "row 1 year", + "error": [ + "ROW does not support [date_period] in expression [1 year]" + ], "warning": [] }, { - "query": "row var = false == false", + "query": "row var = now() - 1 year", "error": [], "warning": [] }, { - "query": "row var = now() == \"2022\"", + "query": "row var = now() - 1 YEAR", "error": [], "warning": [] }, { - "query": "row var = \"2022\" == now()", + "query": "row var = now() - 1 Year", "error": [], "warning": [] }, { - "query": "row var = 5 != 0", + "query": "row var = now() + 1 year", "error": [], "warning": [] }, { - "query": "row var = NOT 5 != 0", - "error": [], + "query": "row 1 year + 1 year", + "error": [ + "Argument of [+] must be [date], found value [1 year] type [duration]" + ], "warning": [] }, { - "query": "row var = (numberField != 0)", + "query": "row var = now() * 1 year", "error": [ - "Unknown column [numberField]" + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 year] type [duration]" ], "warning": [] }, { - "query": "row var = (NOT (5 != 0))", - "error": [], + "query": "row var = now() / 1 year", + "error": [ + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 year] type [duration]" + ], "warning": [] }, { - "query": "row var = to_ip(\"127.0.0.1\") != to_ip(\"127.0.0.1\")", - "error": [], + "query": "row var = now() % 1 year", + "error": [ + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 year] type [duration]" + ], "warning": [] }, { - "query": "row var = now() != now()", - "error": [], + "query": "row 1 years", + "error": [ + "ROW does not support [date_period] in expression [1 years]" + ], "warning": [] }, { - "query": "row var = false != false", - "error": [], + "query": "row 1 years", + "error": [ + "ROW does not support [date_period] in expression [1 years]" + ], "warning": [] }, { - "query": "row var = now() != \"2022\"", + "query": "row var = now() - 1 years", "error": [], "warning": [] }, { - "query": "row var = \"2022\" != now()", + "query": "row var = now() - 1 YEARS", "error": [], "warning": [] }, { - "query": "row var = 1 + 1", + "query": "row var = now() - 1 Years", "error": [], "warning": [] }, { - "query": "row var = (5 + 1)", + "query": "row var = now() + 1 years", "error": [], "warning": [] }, { - "query": "row var = now() + now()", + "query": "row 1 years + 1 year", "error": [ - "Argument of [+] must be [time_literal], found value [now()] type [date]" + "Argument of [+] must be [date], found value [1 years] type [duration]" ], "warning": [] }, { - "query": "row var = 1 - 1", - "error": [], - "warning": [] - }, - { - "query": "row var = (5 - 1)", - "error": [], - "warning": [] - }, - { - "query": "row var = now() - now()", + "query": "row var = now() * 1 years", "error": [ - "Argument of [-] must be [time_literal], found value [now()] type [date]" + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 years] type [duration]" ], "warning": [] }, { - "query": "row var = 1 * 1", - "error": [], - "warning": [] - }, - { - "query": "row var = (5 * 1)", - "error": [], - "warning": [] - }, - { - "query": "row var = now() * now()", + "query": "row var = now() / 1 years", "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [now()] type [date]" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 years] type [duration]" ], "warning": [] }, { - "query": "row var = 1 / 1", - "error": [], + "query": "row var = now() % 1 years", + "error": [ + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 years] type [duration]" + ], "warning": [] }, { - "query": "row var = (5 / 1)", - "error": [], + "query": "row 1 month", + "error": [ + "ROW does not support [date_period] in expression [1 month]" + ], "warning": [] }, { - "query": "row var = now() / now()", + "query": "row 1 month", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [now()] type [date]" + "ROW does not support [date_period] in expression [1 month]" ], "warning": [] }, { - "query": "row var = 1 % 1", + "query": "row var = now() - 1 month", "error": [], "warning": [] }, { - "query": "row var = (5 % 1)", + "query": "row var = now() - 1 MONTH", "error": [], "warning": [] }, { - "query": "row var = now() % now()", - "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [now()] type [date]" - ], - "warning": [] - }, - { - "query": "row var = \"a\" like \"?a\"", + "query": "row var = now() - 1 Month", "error": [], "warning": [] }, { - "query": "row var = \"a\" NOT like \"?a\"", + "query": "row var = now() + 1 month", "error": [], "warning": [] }, { - "query": "row var = NOT \"a\" like \"?a\"", - "error": [], + "query": "row 1 month + 1 year", + "error": [ + "Argument of [+] must be [date], found value [1 month] type [duration]" + ], "warning": [] }, { - "query": "row var = NOT \"a\" NOT like \"?a\"", - "error": [], + "query": "row var = now() * 1 month", + "error": [ + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 month] type [duration]" + ], "warning": [] }, { - "query": "row var = 5 like \"?a\"", + "query": "row var = now() / 1 month", "error": [ - "Argument of [like] must be [string], found value [5] type [number]" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 month] type [duration]" ], "warning": [] }, { - "query": "row var = 5 NOT like \"?a\"", + "query": "row var = now() % 1 month", "error": [ - "Argument of [not_like] must be [string], found value [5] type [number]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 month] type [duration]" ], "warning": [] }, { - "query": "row var = NOT 5 like \"?a\"", + "query": "row 1 months", "error": [ - "Argument of [like] must be [string], found value [5] type [number]" + "ROW does not support [date_period] in expression [1 months]" ], "warning": [] }, { - "query": "row var = NOT 5 NOT like \"?a\"", + "query": "row 1 months", "error": [ - "Argument of [not_like] must be [string], found value [5] type [number]" + "ROW does not support [date_period] in expression [1 months]" ], "warning": [] }, { - "query": "row var = \"a\" rlike \"?a\"", + "query": "row var = now() - 1 months", "error": [], "warning": [] }, { - "query": "row var = \"a\" NOT rlike \"?a\"", + "query": "row var = now() - 1 MONTHS", "error": [], "warning": [] }, { - "query": "row var = NOT \"a\" rlike \"?a\"", + "query": "row var = now() - 1 Months", "error": [], "warning": [] }, { - "query": "row var = NOT \"a\" NOT rlike \"?a\"", + "query": "row var = now() + 1 months", "error": [], "warning": [] }, { - "query": "row var = 5 rlike \"?a\"", + "query": "row 1 months + 1 year", "error": [ - "Argument of [rlike] must be [string], found value [5] type [number]" + "Argument of [+] must be [date], found value [1 months] type [duration]" ], "warning": [] }, { - "query": "row var = 5 NOT rlike \"?a\"", + "query": "row var = now() * 1 months", "error": [ - "Argument of [not_rlike] must be [string], found value [5] type [number]" + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 months] type [duration]" ], "warning": [] }, { - "query": "row var = NOT 5 rlike \"?a\"", + "query": "row var = now() / 1 months", "error": [ - "Argument of [rlike] must be [string], found value [5] type [number]" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 months] type [duration]" ], "warning": [] }, { - "query": "row var = NOT 5 NOT rlike \"?a\"", + "query": "row var = now() % 1 months", "error": [ - "Argument of [not_rlike] must be [string], found value [5] type [number]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 months] type [duration]" ], "warning": [] }, { - "query": "row var = mv_sort([\"a\", \"b\"], \"bogus\")", + "query": "row 1 week", + "error": [ + "ROW does not support [date_period] in expression [1 week]" + ], + "warning": [] + }, + { + "query": "row 1 week", + "error": [ + "ROW does not support [date_period] in expression [1 week]" + ], + "warning": [] + }, + { + "query": "row var = now() - 1 week", "error": [], - "warning": [ - "Invalid option [\"bogus\"] for mv_sort. Supported options: [\"asc\", \"desc\"]." - ] + "warning": [] }, { - "query": "row var = mv_sort([\"a\", \"b\"], \"ASC\")", + "query": "row var = now() - 1 WEEK", "error": [], "warning": [] }, { - "query": "row var = mv_sort([\"a\", \"b\"], \"DESC\")", + "query": "row var = now() - 1 Week", "error": [], "warning": [] }, { - "query": "row 1 anno", + "query": "row var = now() + 1 week", + "error": [], + "warning": [] + }, + { + "query": "row 1 week + 1 year", "error": [ - "ROW does not support [date_period] in expression [1 anno]" + "Argument of [+] must be [date], found value [1 week] type [duration]" ], "warning": [] }, { - "query": "row var = 1 anno", + "query": "row var = now() * 1 week", "error": [ - "Unexpected time interval qualifier: 'anno'" + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 week] type [duration]" ], "warning": [] }, { - "query": "row now() + 1 anno", + "query": "row var = now() / 1 week", "error": [ - "Unexpected time interval qualifier: 'anno'" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 week] type [duration]" ], "warning": [] }, { - "query": "row 1 year", + "query": "row var = now() % 1 week", "error": [ - "ROW does not support [date_period] in expression [1 year]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 week] type [duration]" ], "warning": [] }, { - "query": "row 1 year", + "query": "row 1 weeks", "error": [ - "ROW does not support [date_period] in expression [1 year]" + "ROW does not support [date_period] in expression [1 weeks]" ], "warning": [] }, { - "query": "row var = now() - 1 year", + "query": "row 1 weeks", + "error": [ + "ROW does not support [date_period] in expression [1 weeks]" + ], + "warning": [] + }, + { + "query": "row var = now() - 1 weeks", "error": [], "warning": [] }, { - "query": "row var = now() - 1 YEAR", + "query": "row var = now() - 1 WEEKS", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Year", + "query": "row var = now() - 1 Weeks", "error": [], "warning": [] }, { - "query": "row var = now() + 1 year", + "query": "row var = now() + 1 weeks", "error": [], "warning": [] }, { - "query": "row 1 year + 1 year", + "query": "row 1 weeks + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 year] type [duration]" + "Argument of [+] must be [date], found value [1 weeks] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 year", + "query": "row var = now() * 1 weeks", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 year] type [duration]" + "Argument of [*] must be [number], found value [1 weeks] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 year", + "query": "row var = now() / 1 weeks", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 year] type [duration]" + "Argument of [/] must be [number], found value [1 weeks] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 year", + "query": "row var = now() % 1 weeks", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 year] type [duration]" + "Argument of [%] must be [number], found value [1 weeks] type [duration]" ], "warning": [] }, { - "query": "row 1 years", + "query": "row 1 day", "error": [ - "ROW does not support [date_period] in expression [1 years]" + "ROW does not support [date_period] in expression [1 day]" ], "warning": [] }, { - "query": "row 1 years", + "query": "row 1 day", "error": [ - "ROW does not support [date_period] in expression [1 years]" + "ROW does not support [date_period] in expression [1 day]" ], "warning": [] }, { - "query": "row var = now() - 1 years", + "query": "row var = now() - 1 day", "error": [], "warning": [] }, { - "query": "row var = now() - 1 YEARS", + "query": "row var = now() - 1 DAY", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Years", + "query": "row var = now() - 1 Day", "error": [], "warning": [] }, { - "query": "row var = now() + 1 years", + "query": "row var = now() + 1 day", "error": [], "warning": [] }, { - "query": "row 1 years + 1 year", + "query": "row 1 day + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 years] type [duration]" + "Argument of [+] must be [date], found value [1 day] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 years", + "query": "row var = now() * 1 day", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 years] type [duration]" + "Argument of [*] must be [number], found value [1 day] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 years", + "query": "row var = now() / 1 day", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 years] type [duration]" + "Argument of [/] must be [number], found value [1 day] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 years", + "query": "row var = now() % 1 day", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 years] type [duration]" + "Argument of [%] must be [number], found value [1 day] type [duration]" ], "warning": [] }, { - "query": "row 1 month", + "query": "row 1 days", "error": [ - "ROW does not support [date_period] in expression [1 month]" + "ROW does not support [date_period] in expression [1 days]" ], "warning": [] }, { - "query": "row 1 month", + "query": "row 1 days", "error": [ - "ROW does not support [date_period] in expression [1 month]" + "ROW does not support [date_period] in expression [1 days]" ], "warning": [] }, { - "query": "row var = now() - 1 month", + "query": "row var = now() - 1 days", "error": [], "warning": [] }, { - "query": "row var = now() - 1 MONTH", + "query": "row var = now() - 1 DAYS", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Month", + "query": "row var = now() - 1 Days", "error": [], "warning": [] }, { - "query": "row var = now() + 1 month", + "query": "row var = now() + 1 days", "error": [], "warning": [] }, { - "query": "row 1 month + 1 year", + "query": "row 1 days + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 month] type [duration]" + "Argument of [+] must be [date], found value [1 days] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 month", + "query": "row var = now() * 1 days", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 month] type [duration]" + "Argument of [*] must be [number], found value [1 days] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 month", + "query": "row var = now() / 1 days", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 month] type [duration]" + "Argument of [/] must be [number], found value [1 days] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 month", + "query": "row var = now() % 1 days", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 month] type [duration]" + "Argument of [%] must be [number], found value [1 days] type [duration]" ], "warning": [] }, { - "query": "row 1 months", + "query": "row 1 hour", "error": [ - "ROW does not support [date_period] in expression [1 months]" + "ROW does not support [date_period] in expression [1 hour]" ], "warning": [] }, { - "query": "row 1 months", + "query": "row 1 hour", "error": [ - "ROW does not support [date_period] in expression [1 months]" + "ROW does not support [date_period] in expression [1 hour]" ], "warning": [] }, { - "query": "row var = now() - 1 months", + "query": "row var = now() - 1 hour", "error": [], "warning": [] }, { - "query": "row var = now() - 1 MONTHS", + "query": "row var = now() - 1 HOUR", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Months", + "query": "row var = now() - 1 Hour", "error": [], "warning": [] }, { - "query": "row var = now() + 1 months", + "query": "row var = now() + 1 hour", "error": [], "warning": [] }, { - "query": "row 1 months + 1 year", + "query": "row 1 hour + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 months] type [duration]" + "Argument of [+] must be [date], found value [1 hour] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 months", + "query": "row var = now() * 1 hour", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 months] type [duration]" + "Argument of [*] must be [number], found value [1 hour] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 months", + "query": "row var = now() / 1 hour", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 months] type [duration]" + "Argument of [/] must be [number], found value [1 hour] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 months", + "query": "row var = now() % 1 hour", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 months] type [duration]" + "Argument of [%] must be [number], found value [1 hour] type [duration]" ], "warning": [] }, { - "query": "row 1 week", + "query": "row 1 hours", "error": [ - "ROW does not support [date_period] in expression [1 week]" + "ROW does not support [date_period] in expression [1 hours]" ], "warning": [] }, { - "query": "row 1 week", + "query": "row 1 hours", "error": [ - "ROW does not support [date_period] in expression [1 week]" + "ROW does not support [date_period] in expression [1 hours]" ], "warning": [] }, { - "query": "row var = now() - 1 week", + "query": "row var = now() - 1 hours", "error": [], "warning": [] }, { - "query": "row var = now() - 1 WEEK", + "query": "row var = now() - 1 HOURS", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Week", + "query": "row var = now() - 1 Hours", "error": [], "warning": [] }, { - "query": "row var = now() + 1 week", + "query": "row var = now() + 1 hours", "error": [], "warning": [] }, { - "query": "row 1 week + 1 year", + "query": "row 1 hours + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 week] type [duration]" + "Argument of [+] must be [date], found value [1 hours] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 week", + "query": "row var = now() * 1 hours", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 week] type [duration]" + "Argument of [*] must be [number], found value [1 hours] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 week", + "query": "row var = now() / 1 hours", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 week] type [duration]" + "Argument of [/] must be [number], found value [1 hours] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 week", + "query": "row var = now() % 1 hours", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 week] type [duration]" + "Argument of [%] must be [number], found value [1 hours] type [duration]" ], "warning": [] }, { - "query": "row 1 weeks", + "query": "row 1 minute", "error": [ - "ROW does not support [date_period] in expression [1 weeks]" + "ROW does not support [date_period] in expression [1 minute]" ], "warning": [] }, { - "query": "row 1 weeks", + "query": "row 1 minute", "error": [ - "ROW does not support [date_period] in expression [1 weeks]" + "ROW does not support [date_period] in expression [1 minute]" ], "warning": [] }, { - "query": "row var = now() - 1 weeks", + "query": "row var = now() - 1 minute", "error": [], "warning": [] }, { - "query": "row var = now() - 1 WEEKS", + "query": "row var = now() - 1 MINUTE", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Weeks", + "query": "row var = now() - 1 Minute", "error": [], "warning": [] }, { - "query": "row var = now() + 1 weeks", + "query": "row var = now() + 1 minute", "error": [], "warning": [] }, { - "query": "row 1 weeks + 1 year", + "query": "row 1 minute + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 weeks] type [duration]" + "Argument of [+] must be [date], found value [1 minute] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 weeks", + "query": "row var = now() * 1 minute", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 weeks] type [duration]" + "Argument of [*] must be [number], found value [1 minute] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 weeks", + "query": "row var = now() / 1 minute", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 weeks] type [duration]" + "Argument of [/] must be [number], found value [1 minute] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 weeks", + "query": "row var = now() % 1 minute", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 weeks] type [duration]" + "Argument of [%] must be [number], found value [1 minute] type [duration]" ], "warning": [] }, { - "query": "row 1 day", + "query": "row 1 minutes", "error": [ - "ROW does not support [date_period] in expression [1 day]" + "ROW does not support [date_period] in expression [1 minutes]" ], "warning": [] }, { - "query": "row 1 day", + "query": "row 1 minutes", "error": [ - "ROW does not support [date_period] in expression [1 day]" + "ROW does not support [date_period] in expression [1 minutes]" ], "warning": [] }, { - "query": "row var = now() - 1 day", + "query": "row var = now() - 1 minutes", "error": [], "warning": [] }, { - "query": "row var = now() - 1 DAY", + "query": "row var = now() - 1 MINUTES", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Day", + "query": "row var = now() - 1 Minutes", "error": [], "warning": [] }, { - "query": "row var = now() + 1 day", + "query": "row var = now() + 1 minutes", "error": [], "warning": [] }, { - "query": "row 1 day + 1 year", + "query": "row 1 minutes + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 day] type [duration]" + "Argument of [+] must be [date], found value [1 minutes] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 day", + "query": "row var = now() * 1 minutes", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 day] type [duration]" + "Argument of [*] must be [number], found value [1 minutes] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 day", + "query": "row var = now() / 1 minutes", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 day] type [duration]" + "Argument of [/] must be [number], found value [1 minutes] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 day", + "query": "row var = now() % 1 minutes", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 day] type [duration]" + "Argument of [%] must be [number], found value [1 minutes] type [duration]" ], "warning": [] }, { - "query": "row 1 days", + "query": "row 1 second", "error": [ - "ROW does not support [date_period] in expression [1 days]" + "ROW does not support [date_period] in expression [1 second]" ], "warning": [] }, { - "query": "row 1 days", + "query": "row 1 second", "error": [ - "ROW does not support [date_period] in expression [1 days]" + "ROW does not support [date_period] in expression [1 second]" ], "warning": [] }, { - "query": "row var = now() - 1 days", + "query": "row var = now() - 1 second", "error": [], "warning": [] }, { - "query": "row var = now() - 1 DAYS", + "query": "row var = now() - 1 SECOND", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Days", + "query": "row var = now() - 1 Second", "error": [], "warning": [] }, { - "query": "row var = now() + 1 days", + "query": "row var = now() + 1 second", "error": [], "warning": [] }, { - "query": "row 1 days + 1 year", + "query": "row 1 second + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 days] type [duration]" + "Argument of [+] must be [date], found value [1 second] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 days", + "query": "row var = now() * 1 second", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 days] type [duration]" + "Argument of [*] must be [number], found value [1 second] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 days", + "query": "row var = now() / 1 second", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 days] type [duration]" + "Argument of [/] must be [number], found value [1 second] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 days", + "query": "row var = now() % 1 second", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 days] type [duration]" + "Argument of [%] must be [number], found value [1 second] type [duration]" ], "warning": [] }, { - "query": "row 1 hour", + "query": "row 1 seconds", "error": [ - "ROW does not support [date_period] in expression [1 hour]" + "ROW does not support [date_period] in expression [1 seconds]" ], "warning": [] }, { - "query": "row 1 hour", + "query": "row 1 seconds", "error": [ - "ROW does not support [date_period] in expression [1 hour]" + "ROW does not support [date_period] in expression [1 seconds]" ], "warning": [] }, { - "query": "row var = now() - 1 hour", + "query": "row var = now() - 1 seconds", "error": [], "warning": [] }, { - "query": "row var = now() - 1 HOUR", + "query": "row var = now() - 1 SECONDS", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Hour", + "query": "row var = now() - 1 Seconds", "error": [], "warning": [] }, { - "query": "row var = now() + 1 hour", + "query": "row var = now() + 1 seconds", "error": [], "warning": [] }, { - "query": "row 1 hour + 1 year", + "query": "row 1 seconds + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 hour] type [duration]" + "Argument of [+] must be [date], found value [1 seconds] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 hour", + "query": "row var = now() * 1 seconds", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 hour] type [duration]" + "Argument of [*] must be [number], found value [1 seconds] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 hour", + "query": "row var = now() / 1 seconds", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 hour] type [duration]" + "Argument of [/] must be [number], found value [1 seconds] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 hour", + "query": "row var = now() % 1 seconds", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 hour] type [duration]" + "Argument of [%] must be [number], found value [1 seconds] type [duration]" ], "warning": [] }, { - "query": "row 1 hours", + "query": "row 1 millisecond", "error": [ - "ROW does not support [date_period] in expression [1 hours]" + "ROW does not support [date_period] in expression [1 millisecond]" ], "warning": [] }, { - "query": "row 1 hours", + "query": "row 1 millisecond", "error": [ - "ROW does not support [date_period] in expression [1 hours]" + "ROW does not support [date_period] in expression [1 millisecond]" ], "warning": [] }, { - "query": "row var = now() - 1 hours", + "query": "row var = now() - 1 millisecond", "error": [], "warning": [] }, { - "query": "row var = now() - 1 HOURS", + "query": "row var = now() - 1 MILLISECOND", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Hours", + "query": "row var = now() - 1 Millisecond", "error": [], "warning": [] }, { - "query": "row var = now() + 1 hours", + "query": "row var = now() + 1 millisecond", "error": [], "warning": [] }, { - "query": "row 1 hours + 1 year", + "query": "row 1 millisecond + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 hours] type [duration]" + "Argument of [+] must be [date], found value [1 millisecond] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 hours", + "query": "row var = now() * 1 millisecond", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 hours] type [duration]" + "Argument of [*] must be [number], found value [1 millisecond] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 hours", + "query": "row var = now() / 1 millisecond", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 hours] type [duration]" + "Argument of [/] must be [number], found value [1 millisecond] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 hours", + "query": "row var = now() % 1 millisecond", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 hours] type [duration]" + "Argument of [%] must be [number], found value [1 millisecond] type [duration]" ], "warning": [] }, { - "query": "row 1 minute", + "query": "row 1 milliseconds", "error": [ - "ROW does not support [date_period] in expression [1 minute]" + "ROW does not support [date_period] in expression [1 milliseconds]" ], "warning": [] }, { - "query": "row 1 minute", + "query": "row 1 milliseconds", "error": [ - "ROW does not support [date_period] in expression [1 minute]" + "ROW does not support [date_period] in expression [1 milliseconds]" ], "warning": [] }, { - "query": "row var = now() - 1 minute", + "query": "row var = now() - 1 milliseconds", "error": [], "warning": [] }, { - "query": "row var = now() - 1 MINUTE", + "query": "row var = now() - 1 MILLISECONDS", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Minute", + "query": "row var = now() - 1 Milliseconds", "error": [], "warning": [] }, { - "query": "row var = now() + 1 minute", + "query": "row var = now() + 1 milliseconds", "error": [], "warning": [] }, { - "query": "row 1 minute + 1 year", + "query": "row 1 milliseconds + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 minute] type [duration]" + "Argument of [+] must be [date], found value [1 milliseconds] type [duration]" ], "warning": [] }, { - "query": "row var = now() * 1 minute", + "query": "row var = now() * 1 milliseconds", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 minute] type [duration]" + "Argument of [*] must be [number], found value [1 milliseconds] type [duration]" ], "warning": [] }, { - "query": "row var = now() / 1 minute", + "query": "row var = now() / 1 milliseconds", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 minute] type [duration]" + "Argument of [/] must be [number], found value [1 milliseconds] type [duration]" ], "warning": [] }, { - "query": "row var = now() % 1 minute", + "query": "row var = now() % 1 milliseconds", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 minute] type [duration]" + "Argument of [%] must be [number], found value [1 milliseconds] type [duration]" ], "warning": [] }, { - "query": "row 1 minutes", + "query": "meta", "error": [ - "ROW does not support [date_period] in expression [1 minutes]" + "SyntaxError: missing 'functions' at ''" ], "warning": [] }, { - "query": "row 1 minutes", + "query": "meta functions", + "error": [], + "warning": [] + }, + { + "query": "meta functions()", "error": [ - "ROW does not support [date_period] in expression [1 minutes]" + "SyntaxError: token recognition error at: '('", + "SyntaxError: token recognition error at: ')'" ], "warning": [] }, { - "query": "row var = now() - 1 minutes", - "error": [], + "query": "meta functions blah", + "error": [ + "SyntaxError: token recognition error at: 'b'", + "SyntaxError: token recognition error at: 'l'", + "SyntaxError: token recognition error at: 'a'", + "SyntaxError: token recognition error at: 'h'" + ], "warning": [] }, { - "query": "row var = now() - 1 MINUTES", - "error": [], + "query": "meta info", + "error": [ + "SyntaxError: token recognition error at: 'i'", + "SyntaxError: token recognition error at: 'n'", + "SyntaxError: token recognition error at: 'fo'", + "SyntaxError: missing 'functions' at ''" + ], "warning": [] }, { - "query": "row var = now() - 1 Minutes", - "error": [], + "query": "show", + "error": [ + "SyntaxError: missing 'info' at ''" + ], "warning": [] }, { - "query": "row var = now() + 1 minutes", + "query": "show functions", + "error": [ + "SyntaxError: token recognition error at: 'f'", + "SyntaxError: token recognition error at: 'u'", + "SyntaxError: token recognition error at: 'n'", + "SyntaxError: token recognition error at: 'c'", + "SyntaxError: token recognition error at: 't'", + "SyntaxError: token recognition error at: 'io'", + "SyntaxError: token recognition error at: 'n'", + "SyntaxError: token recognition error at: 's'", + "SyntaxError: missing 'info' at ''" + ], + "warning": [] + }, + { + "query": "show info", "error": [], "warning": [] }, { - "query": "row 1 minutes + 1 year", + "query": "show numberField", "error": [ - "Argument of [+] must be [date], found value [1 minutes] type [duration]" + "SyntaxError: token recognition error at: 'n'", + "SyntaxError: token recognition error at: 'u'", + "SyntaxError: token recognition error at: 'm'", + "SyntaxError: token recognition error at: 'b'", + "SyntaxError: token recognition error at: 'e'", + "SyntaxError: token recognition error at: 'r'", + "SyntaxError: token recognition error at: 'F'", + "SyntaxError: token recognition error at: 'ie'", + "SyntaxError: token recognition error at: 'l'", + "SyntaxError: token recognition error at: 'd'", + "SyntaxError: missing 'info' at ''" ], "warning": [] }, { - "query": "row var = now() * 1 minutes", + "query": "from index | limit ", "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 minutes] type [duration]" + "SyntaxError: missing INTEGER_LITERAL at ''" ], "warning": [] }, { - "query": "row var = now() / 1 minutes", + "query": "from index | limit 4 ", + "error": [], + "warning": [] + }, + { + "query": "from index | limit 4.5", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 minutes] type [duration]" + "SyntaxError: mismatched input '4.5' expecting INTEGER_LITERAL" ], "warning": [] }, { - "query": "row var = now() % 1 minutes", + "query": "from index | limit a", "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 minutes] type [duration]" + "SyntaxError: mismatched input 'a' expecting INTEGER_LITERAL" ], "warning": [] }, { - "query": "row 1 second", + "query": "from index | limit numberField", "error": [ - "ROW does not support [date_period] in expression [1 second]" + "SyntaxError: mismatched input 'numberField' expecting INTEGER_LITERAL" ], "warning": [] }, { - "query": "row 1 second", + "query": "from index | limit stringField", "error": [ - "ROW does not support [date_period] in expression [1 second]" + "SyntaxError: mismatched input 'stringField' expecting INTEGER_LITERAL" ], "warning": [] }, { - "query": "row var = now() - 1 second", + "query": "from index | limit 4", "error": [], "warning": [] }, { - "query": "row var = now() - 1 SECOND", + "query": "ROW a=1::LONG | LOOKUP t ON a", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Second", + "query": "from index | keep ", + "error": [ + "SyntaxError: missing ID_PATTERN at ''" + ], + "warning": [] + }, + { + "query": "from index | keep stringField, numberField, dateField", "error": [], "warning": [] }, { - "query": "row var = now() + 1 second", + "query": "from index | keep `stringField`, `numberField`, `dateField`", "error": [], "warning": [] }, { - "query": "row 1 second + 1 year", + "query": "from index | keep 4.5", "error": [ - "Argument of [+] must be [date], found value [1 second] type [duration]" + "SyntaxError: token recognition error at: '4'", + "SyntaxError: token recognition error at: '5'", + "SyntaxError: missing ID_PATTERN at '.'", + "SyntaxError: missing ID_PATTERN at ''" ], "warning": [] }, { - "query": "row var = now() * 1 second", + "query": "from index | keep `4.5`", "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 second] type [duration]" + "Unknown column [4.5]" ], "warning": [] }, { - "query": "row var = now() / 1 second", + "query": "from index | keep missingField, numberField, dateField", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 second] type [duration]" + "Unknown column [missingField]" ], "warning": [] }, { - "query": "row var = now() % 1 second", + "query": "from index | keep `any#Char$Field`", + "error": [], + "warning": [] + }, + { + "query": "from index | project ", "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 second] type [duration]" + "SyntaxError: mismatched input 'project' expecting {'dissect', 'drop', 'enrich', 'eval', 'grok', 'inlinestats', 'keep', 'limit', 'lookup', 'mv_expand', 'rename', 'sort', 'stats', 'where'}" ], "warning": [] }, { - "query": "row 1 seconds", + "query": "from index | project stringField, numberField, dateField", "error": [ - "ROW does not support [date_period] in expression [1 seconds]" + "SyntaxError: mismatched input 'project' expecting {'dissect', 'drop', 'enrich', 'eval', 'grok', 'inlinestats', 'keep', 'limit', 'lookup', 'mv_expand', 'rename', 'sort', 'stats', 'where'}" ], "warning": [] }, { - "query": "row 1 seconds", + "query": "from index | PROJECT stringField, numberField, dateField", "error": [ - "ROW does not support [date_period] in expression [1 seconds]" + "SyntaxError: mismatched input 'PROJECT' expecting {'dissect', 'drop', 'enrich', 'eval', 'grok', 'inlinestats', 'keep', 'limit', 'lookup', 'mv_expand', 'rename', 'sort', 'stats', 'where'}" ], "warning": [] }, { - "query": "row var = now() - 1 seconds", - "error": [], + "query": "from index | project missingField, numberField, dateField", + "error": [ + "SyntaxError: mismatched input 'project' expecting {'dissect', 'drop', 'enrich', 'eval', 'grok', 'inlinestats', 'keep', 'limit', 'lookup', 'mv_expand', 'rename', 'sort', 'stats', 'where'}" + ], "warning": [] }, { - "query": "row var = now() - 1 SECONDS", + "query": "from index | keep s*", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Seconds", + "query": "from index | keep *Field", "error": [], "warning": [] }, { - "query": "row var = now() + 1 seconds", + "query": "from index | keep s*Field", "error": [], "warning": [] }, { - "query": "row 1 seconds + 1 year", - "error": [ - "Argument of [+] must be [date], found value [1 seconds] type [duration]" - ], + "query": "from index | keep string*Field", + "error": [], "warning": [] }, { - "query": "row var = now() * 1 seconds", - "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 seconds] type [duration]" - ], + "query": "from index | keep s*, n*", + "error": [], "warning": [] }, { - "query": "row var = now() / 1 seconds", + "query": "from index | keep m*", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 seconds] type [duration]" + "Unknown column [m*]" ], "warning": [] }, { - "query": "row var = now() % 1 seconds", + "query": "from index | keep *m", "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 seconds] type [duration]" + "Unknown column [*m]" ], "warning": [] }, { - "query": "row 1 millisecond", + "query": "from index | keep d*m", "error": [ - "ROW does not support [date_period] in expression [1 millisecond]" + "Unknown column [d*m]" ], "warning": [] }, { - "query": "row 1 millisecond", - "error": [ - "ROW does not support [date_period] in expression [1 millisecond]" - ], - "warning": [] + "query": "from unsupported_index | keep unsupported_field", + "error": [], + "warning": [ + "Field [unsupported_field] cannot be retrieved, it is unsupported or not indexed; returning null" + ] }, { - "query": "row var = now() - 1 millisecond", + "query": "FROM index | STATS ROUND(AVG(numberField * 1.5)), COUNT(*), MIN(numberField * 10) | KEEP `MIN(numberField * 10)`", "error": [], "warning": [] }, { - "query": "row var = now() - 1 MILLISECOND", + "query": "FROM index | STATS COUNT(*), MIN(numberField * 10), MAX(numberField)| KEEP `COUNT(*)`", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Millisecond", - "error": [], + "query": "from index | drop ", + "error": [ + "SyntaxError: missing ID_PATTERN at ''" + ], "warning": [] }, { - "query": "row var = now() + 1 millisecond", + "query": "from index | drop stringField, numberField, dateField", "error": [], "warning": [] }, { - "query": "row 1 millisecond + 1 year", + "query": "from index | drop 4.5", "error": [ - "Argument of [+] must be [date], found value [1 millisecond] type [duration]" - ], - "warning": [] - }, - { - "query": "row var = now() * 1 millisecond", - "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 millisecond] type [duration]" - ], - "warning": [] - }, - { - "query": "row var = now() / 1 millisecond", - "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 millisecond] type [duration]" - ], - "warning": [] - }, - { - "query": "row var = now() % 1 millisecond", - "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 millisecond] type [duration]" - ], - "warning": [] - }, - { - "query": "row 1 milliseconds", - "error": [ - "ROW does not support [date_period] in expression [1 milliseconds]" + "SyntaxError: token recognition error at: '4'", + "SyntaxError: token recognition error at: '5'", + "SyntaxError: missing ID_PATTERN at '.'", + "SyntaxError: missing ID_PATTERN at ''" ], "warning": [] }, { - "query": "row 1 milliseconds", + "query": "from index | drop missingField, numberField, dateField", "error": [ - "ROW does not support [date_period] in expression [1 milliseconds]" + "Unknown column [missingField]" ], "warning": [] }, { - "query": "row var = now() - 1 milliseconds", + "query": "from index | drop `any#Char$Field`", "error": [], "warning": [] }, { - "query": "row var = now() - 1 MILLISECONDS", + "query": "from index | drop s*", "error": [], "warning": [] }, { - "query": "row var = now() - 1 Milliseconds", + "query": "from index | drop s**Field", "error": [], "warning": [] }, { - "query": "row var = now() + 1 milliseconds", + "query": "from index | drop *Field*", "error": [], "warning": [] }, { - "query": "row 1 milliseconds + 1 year", - "error": [ - "Argument of [+] must be [date], found value [1 milliseconds] type [duration]" - ], - "warning": [] - }, - { - "query": "row var = now() * 1 milliseconds", - "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 milliseconds] type [duration]" - ], - "warning": [] - }, - { - "query": "row var = now() / 1 milliseconds", - "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 milliseconds] type [duration]" - ], - "warning": [] - }, - { - "query": "row var = now() % 1 milliseconds", - "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 milliseconds] type [duration]" - ], - "warning": [] - }, - { - "query": "meta", - "error": [ - "SyntaxError: missing 'functions' at ''" - ], - "warning": [] - }, - { - "query": "meta functions", + "query": "from index | drop s*F*d", "error": [], "warning": [] }, { - "query": "meta functions()", - "error": [ - "SyntaxError: token recognition error at: '('", - "SyntaxError: token recognition error at: ')'" - ], - "warning": [] - }, - { - "query": "meta functions blah", - "error": [ - "SyntaxError: token recognition error at: 'b'", - "SyntaxError: token recognition error at: 'l'", - "SyntaxError: token recognition error at: 'a'", - "SyntaxError: token recognition error at: 'h'" - ], - "warning": [] - }, - { - "query": "meta info", - "error": [ - "SyntaxError: token recognition error at: 'i'", - "SyntaxError: token recognition error at: 'n'", - "SyntaxError: token recognition error at: 'fo'", - "SyntaxError: missing 'functions' at ''" - ], - "warning": [] - }, - { - "query": "show", - "error": [ - "SyntaxError: missing 'info' at ''" - ], + "query": "from index | drop *Field", + "error": [], "warning": [] }, { - "query": "show functions", - "error": [ - "SyntaxError: token recognition error at: 'f'", - "SyntaxError: token recognition error at: 'u'", - "SyntaxError: token recognition error at: 'n'", - "SyntaxError: token recognition error at: 'c'", - "SyntaxError: token recognition error at: 't'", - "SyntaxError: token recognition error at: 'io'", - "SyntaxError: token recognition error at: 'n'", - "SyntaxError: token recognition error at: 's'", - "SyntaxError: missing 'info' at ''" - ], + "query": "from index | drop s*Field", + "error": [], "warning": [] }, { - "query": "show info", + "query": "from index | drop string*Field", "error": [], "warning": [] }, { - "query": "show numberField", - "error": [ - "SyntaxError: token recognition error at: 'n'", - "SyntaxError: token recognition error at: 'u'", - "SyntaxError: token recognition error at: 'm'", - "SyntaxError: token recognition error at: 'b'", - "SyntaxError: token recognition error at: 'e'", - "SyntaxError: token recognition error at: 'r'", - "SyntaxError: token recognition error at: 'F'", - "SyntaxError: token recognition error at: 'ie'", - "SyntaxError: token recognition error at: 'l'", - "SyntaxError: token recognition error at: 'd'", - "SyntaxError: missing 'info' at ''" - ], + "query": "from index | drop s*, n*", + "error": [], "warning": [] }, { - "query": "from index | limit ", + "query": "from index | drop m*", "error": [ - "SyntaxError: missing INTEGER_LITERAL at ''" + "Unknown column [m*]" ], "warning": [] }, { - "query": "from index | limit 4 ", - "error": [], - "warning": [] - }, - { - "query": "from index | limit 4.5", + "query": "from index | drop *m", "error": [ - "SyntaxError: mismatched input '4.5' expecting INTEGER_LITERAL" + "Unknown column [*m]" ], "warning": [] }, { - "query": "from index | limit a", + "query": "from index | drop d*m", "error": [ - "SyntaxError: mismatched input 'a' expecting INTEGER_LITERAL" + "Unknown column [d*m]" ], "warning": [] }, { - "query": "from index | limit numberField", + "query": "from index | drop *", "error": [ - "SyntaxError: mismatched input 'numberField' expecting INTEGER_LITERAL" + "Removing all fields is not allowed [*]" ], "warning": [] }, { - "query": "from index | limit stringField", + "query": "from index | drop stringField, *", "error": [ - "SyntaxError: mismatched input 'stringField' expecting INTEGER_LITERAL" + "Removing all fields is not allowed [*]" ], "warning": [] }, { - "query": "from index | limit 4", + "query": "from index | drop @timestamp", "error": [], - "warning": [] + "warning": [ + "Drop [@timestamp] will remove all time filters to the search results" + ] }, { - "query": "ROW a=1::LONG | LOOKUP t ON a", + "query": "from index | drop stringField, @timestamp", "error": [], - "warning": [] - }, - { - "query": "from index | keep ", - "error": [ - "SyntaxError: missing ID_PATTERN at ''" - ], - "warning": [] + "warning": [ + "Drop [@timestamp] will remove all time filters to the search results" + ] }, { - "query": "from index | keep stringField, numberField, dateField", + "query": "FROM index | STATS ROUND(AVG(numberField * 1.5)), COUNT(*), MIN(numberField * 10) | DROP `MIN(numberField * 10)`", "error": [], "warning": [] }, { - "query": "from index | keep `stringField`, `numberField`, `dateField`", + "query": "FROM index | STATS COUNT(*), MIN(numberField * 10), MAX(numberField)| DROP `COUNT(*)`", "error": [], "warning": [] }, { - "query": "from index | keep 4.5", - "error": [ - "SyntaxError: token recognition error at: '4'", - "SyntaxError: token recognition error at: '5'", - "SyntaxError: missing ID_PATTERN at '.'", - "SyntaxError: missing ID_PATTERN at ''" - ], - "warning": [] - }, - { - "query": "from index | keep `4.5`", - "error": [ - "Unknown column [4.5]" - ], - "warning": [] - }, - { - "query": "from index | keep missingField, numberField, dateField", + "query": "from a_index | mv_expand ", "error": [ - "Unknown column [missingField]" + "SyntaxError: missing {UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER} at ''" ], "warning": [] }, { - "query": "from index | keep `any#Char$Field`", + "query": "from a_index | mv_expand stringField", "error": [], "warning": [] }, { - "query": "from index | project ", - "error": [ - "SyntaxError: mismatched input 'project' expecting {'dissect', 'drop', 'enrich', 'eval', 'grok', 'inlinestats', 'keep', 'limit', 'lookup', 'mv_expand', 'rename', 'sort', 'stats', 'where'}" - ], - "warning": [] - }, - { - "query": "from index | project stringField, numberField, dateField", - "error": [ - "SyntaxError: mismatched input 'project' expecting {'dissect', 'drop', 'enrich', 'eval', 'grok', 'inlinestats', 'keep', 'limit', 'lookup', 'mv_expand', 'rename', 'sort', 'stats', 'where'}" - ], - "warning": [] - }, - { - "query": "from index | PROJECT stringField, numberField, dateField", - "error": [ - "SyntaxError: mismatched input 'PROJECT' expecting {'dissect', 'drop', 'enrich', 'eval', 'grok', 'inlinestats', 'keep', 'limit', 'lookup', 'mv_expand', 'rename', 'sort', 'stats', 'where'}" - ], - "warning": [] - }, - { - "query": "from index | project missingField, numberField, dateField", - "error": [ - "SyntaxError: mismatched input 'project' expecting {'dissect', 'drop', 'enrich', 'eval', 'grok', 'inlinestats', 'keep', 'limit', 'lookup', 'mv_expand', 'rename', 'sort', 'stats', 'where'}" - ], - "warning": [] - }, - { - "query": "from index | keep s*", - "error": [], - "warning": [] - }, - { - "query": "from index | keep *Field", - "error": [], - "warning": [] - }, - { - "query": "from index | keep s*Field", - "error": [], - "warning": [] - }, - { - "query": "from index | keep string*Field", - "error": [], - "warning": [] - }, - { - "query": "from index | keep s*, n*", - "error": [], - "warning": [] - }, - { - "query": "from index | keep m*", - "error": [ - "Unknown column [m*]" - ], - "warning": [] - }, - { - "query": "from index | keep *m", - "error": [ - "Unknown column [*m]" - ], - "warning": [] - }, - { - "query": "from index | keep d*m", - "error": [ - "Unknown column [d*m]" - ], - "warning": [] - }, - { - "query": "from unsupported_index | keep unsupported_field", - "error": [], - "warning": [ - "Field [unsupported_field] cannot be retrieved, it is unsupported or not indexed; returning null" - ] - }, - { - "query": "FROM index | STATS ROUND(AVG(numberField * 1.5)), COUNT(*), MIN(numberField * 10) | KEEP `MIN(numberField * 10)`", - "error": [], - "warning": [] - }, - { - "query": "FROM index | STATS COUNT(*), MIN(numberField * 10), MAX(numberField)| KEEP `COUNT(*)`", - "error": [], - "warning": [] - }, - { - "query": "from index | drop ", - "error": [ - "SyntaxError: missing ID_PATTERN at ''" - ], - "warning": [] - }, - { - "query": "from index | drop stringField, numberField, dateField", - "error": [], - "warning": [] - }, - { - "query": "from index | drop 4.5", - "error": [ - "SyntaxError: token recognition error at: '4'", - "SyntaxError: token recognition error at: '5'", - "SyntaxError: missing ID_PATTERN at '.'", - "SyntaxError: missing ID_PATTERN at ''" - ], - "warning": [] - }, - { - "query": "from index | drop missingField, numberField, dateField", - "error": [ - "Unknown column [missingField]" - ], - "warning": [] - }, - { - "query": "from index | drop `any#Char$Field`", - "error": [], - "warning": [] - }, - { - "query": "from index | drop s*", - "error": [], - "warning": [] - }, - { - "query": "from index | drop s**Field", - "error": [], - "warning": [] - }, - { - "query": "from index | drop *Field*", - "error": [], - "warning": [] - }, - { - "query": "from index | drop s*F*d", - "error": [], - "warning": [] - }, - { - "query": "from index | drop *Field", - "error": [], - "warning": [] - }, - { - "query": "from index | drop s*Field", - "error": [], - "warning": [] - }, - { - "query": "from index | drop string*Field", - "error": [], - "warning": [] - }, - { - "query": "from index | drop s*, n*", - "error": [], - "warning": [] - }, - { - "query": "from index | drop m*", - "error": [ - "Unknown column [m*]" - ], - "warning": [] - }, - { - "query": "from index | drop *m", - "error": [ - "Unknown column [*m]" - ], - "warning": [] - }, - { - "query": "from index | drop d*m", - "error": [ - "Unknown column [d*m]" - ], - "warning": [] - }, - { - "query": "from index | drop *", - "error": [ - "Removing all fields is not allowed [*]" - ], - "warning": [] - }, - { - "query": "from index | drop stringField, *", - "error": [ - "Removing all fields is not allowed [*]" - ], - "warning": [] - }, - { - "query": "from index | drop @timestamp", - "error": [], - "warning": [ - "Drop [@timestamp] will remove all time filters to the search results" - ] - }, - { - "query": "from index | drop stringField, @timestamp", - "error": [], - "warning": [ - "Drop [@timestamp] will remove all time filters to the search results" - ] - }, - { - "query": "FROM index | STATS ROUND(AVG(numberField * 1.5)), COUNT(*), MIN(numberField * 10) | DROP `MIN(numberField * 10)`", - "error": [], - "warning": [] - }, - { - "query": "FROM index | STATS COUNT(*), MIN(numberField * 10), MAX(numberField)| DROP `COUNT(*)`", - "error": [], - "warning": [] - }, - { - "query": "from a_index | mv_expand ", - "error": [ - "SyntaxError: missing {UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER} at ''" - ], - "warning": [] - }, - { - "query": "from a_index | mv_expand stringField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | mv_expand numberField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | mv_expand dateField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | mv_expand booleanField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | mv_expand ipField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | mv_expand numberField, b", - "error": [ - "SyntaxError: token recognition error at: ','", - "SyntaxError: extraneous input 'b' expecting " - ], - "warning": [] - }, - { - "query": "row a = \"a\" | mv_expand a", - "error": [], - "warning": [] - }, - { - "query": "row a = [1, 2, 3] | mv_expand a", - "error": [], - "warning": [] - }, - { - "query": "row a = [true, false] | mv_expand a", - "error": [], - "warning": [] - }, - { - "query": "row a = [\"a\", \"b\"] | mv_expand a", - "error": [], - "warning": [] - }, - { - "query": "from a_index | rename", - "error": [ - "SyntaxError: mismatched input '' expecting ID_PATTERN" - ], - "warning": [] - }, - { - "query": "from a_index | rename stringField", - "error": [ - "SyntaxError: mismatched input '' expecting 'as'" - ], - "warning": [] - }, - { - "query": "from a_index | rename a", - "error": [ - "SyntaxError: mismatched input '' expecting 'as'", - "Unknown column [a]" - ], - "warning": [] - }, - { - "query": "from a_index | rename stringField as", - "error": [ - "SyntaxError: missing ID_PATTERN at ''" - ], - "warning": [] - }, - { - "query": "from a_index | rename missingField as", - "error": [ - "SyntaxError: missing ID_PATTERN at ''", - "Unknown column [missingField]" - ], - "warning": [] - }, - { - "query": "from a_index | rename stringField as b", - "error": [], - "warning": [] - }, - { - "query": "from a_index | rename stringField AS b", - "error": [], - "warning": [] - }, - { - "query": "from a_index | rename stringField As b", - "error": [], - "warning": [] - }, - { - "query": "from a_index | rename stringField As b, b AS c", - "error": [], - "warning": [] - }, - { - "query": "from a_index | rename fn() as a", - "error": [ - "SyntaxError: token recognition error at: '('", - "SyntaxError: token recognition error at: ')'", - "Unknown column [fn]", - "Unknown column [a]" - ], - "warning": [] - }, - { - "query": "from a_index | eval numberField + 1 | rename `numberField + 1` as a", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats avg(numberField) | rename `avg(numberField)` as avg0", - "error": [], - "warning": [] - }, - { - "query": "from a_index |eval numberField + 1 | rename `numberField + 1` as ", - "error": [ - "SyntaxError: missing ID_PATTERN at ''" - ], - "warning": [] - }, - { - "query": "from a_index | rename s* as strings", - "error": [ - "Using wildcards (*) in RENAME is not allowed [s*]", - "Unknown column [strings]" - ], - "warning": [] - }, - { - "query": "row a = 10 | rename a as `this``is fine`", - "error": [], - "warning": [] - }, - { - "query": "row a = 10 | rename a as this is fine", - "error": [ - "SyntaxError: mismatched input 'is' expecting " - ], - "warning": [] - }, - { - "query": "from a_index | dissect", - "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField", - "error": [ - "SyntaxError: missing QUOTED_STRING at ''" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField 2", - "error": [ - "SyntaxError: mismatched input '2' expecting QUOTED_STRING" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField .", - "error": [ - "SyntaxError: mismatched input '' expecting {UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - "Unknown column [stringField.]" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField %a", - "error": [ - "SyntaxError: mismatched input '%' expecting QUOTED_STRING", - "SyntaxError: mismatched input '' expecting '='" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField \"%{firstWord}\"", - "error": [], - "warning": [] - }, - { - "query": "from a_index | dissect numberField \"%{firstWord}\"", - "error": [ - "DISSECT only supports string type values, found [numberField] of type [number]" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField \"%{firstWord}\" option ", - "error": [ - "SyntaxError: mismatched input '' expecting '='" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField \"%{firstWord}\" option = ", - "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET}", - "Invalid option for DISSECT: [option]" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField \"%{firstWord}\" option = 1", - "error": [ - "Invalid option for DISSECT: [option]" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField \"%{firstWord}\" append_separator = \"-\"", - "error": [], - "warning": [] - }, - { - "query": "from a_index | dissect stringField \"%{firstWord}\" ignore_missing = true", - "error": [ - "Invalid option for DISSECT: [ignore_missing]" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField \"%{firstWord}\" append_separator = true", - "error": [ - "Invalid value for DISSECT append_separator: expected a string, but was [true]" - ], - "warning": [] - }, - { - "query": "from a_index | dissect stringField \"%{firstWord}\" | keep firstWord", - "error": [], - "warning": [] - }, - { - "query": "from a_index | grok", - "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], - "warning": [] - }, - { - "query": "from a_index | grok stringField", - "error": [ - "SyntaxError: missing QUOTED_STRING at ''" - ], - "warning": [] - }, - { - "query": "from a_index | grok stringField 2", - "error": [ - "SyntaxError: mismatched input '2' expecting QUOTED_STRING" - ], - "warning": [] - }, - { - "query": "from a_index | grok stringField .", - "error": [ - "SyntaxError: mismatched input '' expecting {UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - "Unknown column [stringField.]" - ], - "warning": [] - }, - { - "query": "from a_index | grok stringField %a", - "error": [ - "SyntaxError: mismatched input '%' expecting QUOTED_STRING" - ], - "warning": [] - }, - { - "query": "from a_index | grok stringField \"%{firstWord}\"", - "error": [], - "warning": [] - }, - { - "query": "from a_index | grok numberField \"%{firstWord}\"", - "error": [ - "GROK only supports string type values, found [numberField] of type [number]" - ], - "warning": [] - }, - { - "query": "from a_index | grok stringField \"%{firstWord}\" | keep firstWord", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where b", - "error": [ - "Unknown column [b]" - ], - "warning": [] - }, - { - "query": "from a_index | where true", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT true", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where false", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT false", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where 1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT 1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where +1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT +1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where 1 * 1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT 1 * 1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where -1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT -1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where 1 / 1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT 1 / 1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where 1.0 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT 1.0 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where 1.5 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT 1.5 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where numberField > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT numberField > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where (numberField > 0)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where (NOT (numberField > 0))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where 1 > 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where stringField > stringField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where numberField > numberField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where dateField > dateField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where booleanField > booleanField", - "error": [ - "Argument of [>] must be [number], found value [booleanField] type [boolean]", - "Argument of [>] must be [number], found value [booleanField] type [boolean]" - ], - "warning": [] - }, - { - "query": "from a_index | where ipField > ipField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where numberField >= 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT numberField >= 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where (numberField >= 0)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where (NOT (numberField >= 0))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where 1 >= 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where stringField >= stringField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where numberField >= numberField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where dateField >= dateField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where booleanField >= booleanField", - "error": [ - "Argument of [>=] must be [number], found value [booleanField] type [boolean]", - "Argument of [>=] must be [number], found value [booleanField] type [boolean]" - ], - "warning": [] - }, - { - "query": "from a_index | where ipField >= ipField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where numberField < 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT numberField < 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where (numberField < 0)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where (NOT (numberField < 0))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where 1 < 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where stringField < stringField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where numberField < numberField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where dateField < dateField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where booleanField < booleanField", - "error": [ - "Argument of [<] must be [number], found value [booleanField] type [boolean]", - "Argument of [<] must be [number], found value [booleanField] type [boolean]" - ], - "warning": [] - }, - { - "query": "from a_index | where ipField < ipField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where numberField <= 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where NOT numberField <= 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where (numberField <= 0)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where (NOT (numberField <= 0))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where 1 <= 0", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where stringField <= stringField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where numberField <= numberField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where dateField <= dateField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where booleanField <= booleanField", - "error": [ - "Argument of [<=] must be [number], found value [booleanField] type [boolean]", - "Argument of [<=] must be [number], found value [booleanField] type [boolean]" - ], - "warning": [] - }, - { - "query": "from a_index | where ipField <= ipField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where numberField == 0", + "query": "from a_index | mv_expand numberField", "error": [], "warning": [] }, { - "query": "from a_index | where NOT numberField == 0", + "query": "from a_index | mv_expand dateField", "error": [], "warning": [] }, { - "query": "from a_index | where (numberField == 0)", + "query": "from a_index | mv_expand booleanField", "error": [], "warning": [] }, { - "query": "from a_index | where (NOT (numberField == 0))", + "query": "from a_index | mv_expand ipField", "error": [], "warning": [] }, { - "query": "from a_index | where 1 == 0", - "error": [], + "query": "from a_index | mv_expand numberField, b", + "error": [ + "SyntaxError: token recognition error at: ','", + "SyntaxError: extraneous input 'b' expecting " + ], "warning": [] }, { - "query": "from a_index | where stringField == stringField", + "query": "row a = \"a\" | mv_expand a", "error": [], "warning": [] }, { - "query": "from a_index | where numberField == numberField", + "query": "row a = [1, 2, 3] | mv_expand a", "error": [], "warning": [] }, { - "query": "from a_index | where dateField == dateField", + "query": "row a = [true, false] | mv_expand a", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField == booleanField", + "query": "row a = [\"a\", \"b\"] | mv_expand a", "error": [], "warning": [] }, { - "query": "from a_index | where ipField == ipField", - "error": [], + "query": "from a_index | rename", + "error": [ + "SyntaxError: mismatched input '' expecting ID_PATTERN" + ], "warning": [] }, { - "query": "from a_index | where numberField != 0", - "error": [], + "query": "from a_index | rename stringField", + "error": [ + "SyntaxError: mismatched input '' expecting 'as'" + ], "warning": [] }, { - "query": "from a_index | where NOT numberField != 0", - "error": [], + "query": "from a_index | rename a", + "error": [ + "SyntaxError: mismatched input '' expecting 'as'", + "Unknown column [a]" + ], "warning": [] }, { - "query": "from a_index | where (numberField != 0)", - "error": [], + "query": "from a_index | rename stringField as", + "error": [ + "SyntaxError: missing ID_PATTERN at ''" + ], "warning": [] }, { - "query": "from a_index | where (NOT (numberField != 0))", - "error": [], + "query": "from a_index | rename missingField as", + "error": [ + "SyntaxError: missing ID_PATTERN at ''", + "Unknown column [missingField]" + ], "warning": [] }, { - "query": "from a_index | where 1 != 0", + "query": "from a_index | rename stringField as b", "error": [], "warning": [] }, { - "query": "from a_index | where stringField != stringField", + "query": "from a_index | rename stringField AS b", "error": [], "warning": [] }, { - "query": "from a_index | where numberField != numberField", + "query": "from a_index | rename stringField As b", "error": [], "warning": [] }, { - "query": "from a_index | where dateField != dateField", + "query": "from a_index | rename stringField As b, b AS c", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField != booleanField", - "error": [], + "query": "from a_index | rename fn() as a", + "error": [ + "SyntaxError: token recognition error at: '('", + "SyntaxError: token recognition error at: ')'", + "Unknown column [fn]", + "Unknown column [a]" + ], "warning": [] }, { - "query": "from a_index | where ipField != ipField", + "query": "from a_index | eval numberField + 1 | rename `numberField + 1` as a", "error": [], "warning": [] }, { - "query": "from a_index | where - numberField > 0", + "query": "from a_index | stats avg(numberField) | rename `avg(numberField)` as avg0", "error": [], "warning": [] }, { - "query": "from a_index | where - round(numberField) > 0", - "error": [], + "query": "from a_index |eval numberField + 1 | rename `numberField + 1` as ", + "error": [ + "SyntaxError: missing ID_PATTERN at ''" + ], "warning": [] }, { - "query": "from a_index | where 1 + - numberField > 0", - "error": [], + "query": "from a_index | rename s* as strings", + "error": [ + "Using wildcards (*) in RENAME is not allowed [s*]", + "Unknown column [strings]" + ], "warning": [] }, { - "query": "from a_index | where 1 - numberField > 0", + "query": "row a = 10 | rename a as `this``is fine`", "error": [], "warning": [] }, { - "query": "from a_index | where - numberField > 0", - "error": [], + "query": "row a = 10 | rename a as this is fine", + "error": [ + "SyntaxError: mismatched input 'is' expecting " + ], "warning": [] }, { - "query": "from a_index | where - round(numberField) > 0", - "error": [], + "query": "from a_index | dissect", + "error": [ + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + ], "warning": [] }, { - "query": "from a_index | where 1 + - numberField > 0", - "error": [], + "query": "from a_index | dissect stringField", + "error": [ + "SyntaxError: missing QUOTED_STRING at ''" + ], "warning": [] }, { - "query": "from a_index | where 1 - numberField > 0", - "error": [], + "query": "from a_index | dissect stringField 2", + "error": [ + "SyntaxError: mismatched input '2' expecting QUOTED_STRING" + ], "warning": [] }, { - "query": "from a_index | where + numberField > 0", - "error": [], + "query": "from a_index | dissect stringField .", + "error": [ + "SyntaxError: mismatched input '' expecting {UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "Unknown column [stringField.]" + ], "warning": [] }, { - "query": "from a_index | where + round(numberField) > 0", - "error": [], + "query": "from a_index | dissect stringField %a", + "error": [ + "SyntaxError: mismatched input '%' expecting QUOTED_STRING", + "SyntaxError: mismatched input '' expecting '='" + ], "warning": [] }, { - "query": "from a_index | where 1 + + numberField > 0", + "query": "from a_index | dissect stringField \"%{firstWord}\"", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + numberField > 0", - "error": [], + "query": "from a_index | dissect numberField \"%{firstWord}\"", + "error": [ + "DISSECT only supports string type values, found [numberField] of type [number]" + ], "warning": [] }, { - "query": "from a_index | where + numberField > 0", - "error": [], + "query": "from a_index | dissect stringField \"%{firstWord}\" option ", + "error": [ + "SyntaxError: mismatched input '' expecting '='" + ], "warning": [] }, { - "query": "from a_index | where + round(numberField) > 0", - "error": [], + "query": "from a_index | dissect stringField \"%{firstWord}\" option = ", + "error": [ + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET}", + "Invalid option for DISSECT: [option]" + ], "warning": [] }, { - "query": "from a_index | where 1 + + numberField > 0", - "error": [], + "query": "from a_index | dissect stringField \"%{firstWord}\" option = 1", + "error": [ + "Invalid option for DISSECT: [option]" + ], "warning": [] }, { - "query": "from a_index | where 1 + numberField > 0", + "query": "from a_index | dissect stringField \"%{firstWord}\" append_separator = \"-\"", "error": [], "warning": [] }, { - "query": "from a_index | where not booleanField", - "error": [], + "query": "from a_index | dissect stringField \"%{firstWord}\" ignore_missing = true", + "error": [ + "Invalid option for DISSECT: [ignore_missing]" + ], "warning": [] }, { - "query": "from a_index | where -- numberField > 0", - "error": [], + "query": "from a_index | dissect stringField \"%{firstWord}\" append_separator = true", + "error": [ + "Invalid value for DISSECT append_separator: expected a string, but was [true]" + ], "warning": [] }, { - "query": "from a_index | where -- round(numberField) > 0", + "query": "from a_index | dissect stringField \"%{firstWord}\" | keep firstWord", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + -- numberField > 0", - "error": [], + "query": "from a_index | grok", + "error": [ + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + ], "warning": [] }, { - "query": "from a_index | where 1 -- numberField > 0", - "error": [], + "query": "from a_index | grok stringField", + "error": [ + "SyntaxError: missing QUOTED_STRING at ''" + ], "warning": [] }, { - "query": "from a_index | where -+ numberField > 0", - "error": [], + "query": "from a_index | grok stringField 2", + "error": [ + "SyntaxError: mismatched input '2' expecting QUOTED_STRING" + ], "warning": [] }, { - "query": "from a_index | where -+ round(numberField) > 0", - "error": [], + "query": "from a_index | grok stringField .", + "error": [ + "SyntaxError: mismatched input '' expecting {UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "Unknown column [stringField.]" + ], "warning": [] }, { - "query": "from a_index | where 1 + -+ numberField > 0", - "error": [], + "query": "from a_index | grok stringField %a", + "error": [ + "SyntaxError: mismatched input '%' expecting QUOTED_STRING" + ], "warning": [] }, { - "query": "from a_index | where 1 -+ numberField > 0", + "query": "from a_index | grok stringField \"%{firstWord}\"", "error": [], "warning": [] }, { - "query": "from a_index | where +- numberField > 0", - "error": [], + "query": "from a_index | grok numberField \"%{firstWord}\"", + "error": [ + "GROK only supports string type values, found [numberField] of type [number]" + ], "warning": [] }, { - "query": "from a_index | where +- round(numberField) > 0", + "query": "from a_index | grok stringField \"%{firstWord}\" | keep firstWord", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + +- numberField > 0", - "error": [], + "query": "from a_index | where b", + "error": [ + "Unknown column [b]" + ], "warning": [] }, { - "query": "from a_index | where 1 +- numberField > 0", + "query": "from a_index | where true", "error": [], "warning": [] }, { - "query": "from a_index | where ++ numberField > 0", + "query": "from a_index | where NOT true", "error": [], "warning": [] }, { - "query": "from a_index | where ++ round(numberField) > 0", + "query": "from a_index | where false", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + ++ numberField > 0", + "query": "from a_index | where NOT false", "error": [], "warning": [] }, { - "query": "from a_index | where 1 ++ numberField > 0", + "query": "from a_index | where 1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where not not booleanField", + "query": "from a_index | where NOT 1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where --- numberField > 0", + "query": "from a_index | where +1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where --- round(numberField) > 0", + "query": "from a_index | where NOT +1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + --- numberField > 0", + "query": "from a_index | where 1 * 1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 --- numberField > 0", + "query": "from a_index | where NOT 1 * 1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where -+- numberField > 0", + "query": "from a_index | where -1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where -+- round(numberField) > 0", + "query": "from a_index | where NOT -1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + -+- numberField > 0", + "query": "from a_index | where 1 / 1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 -+- numberField > 0", + "query": "from a_index | where NOT 1 / 1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where +-+ numberField > 0", + "query": "from a_index | where 1.0 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where +-+ round(numberField) > 0", + "query": "from a_index | where NOT 1.0 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + +-+ numberField > 0", + "query": "from a_index | where 1.5 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 +-+ numberField > 0", + "query": "from a_index | where NOT 1.5 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where +++ numberField > 0", + "query": "from a_index | where numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where +++ round(numberField) > 0", + "query": "from a_index | where NOT numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + +++ numberField > 0", + "query": "from a_index | where (numberField > 0)", "error": [], "warning": [] }, { - "query": "from a_index | where 1 +++ numberField > 0", + "query": "from a_index | where (NOT (numberField > 0))", "error": [], "warning": [] }, { - "query": "from a_index | where not not not booleanField", + "query": "from a_index | where 1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | where ---- numberField > 0", + "query": "from a_index | where stringField > stringField", "error": [], "warning": [] }, { - "query": "from a_index | where ---- round(numberField) > 0", + "query": "from a_index | where numberField > numberField", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + ---- numberField > 0", + "query": "from a_index | where dateField > dateField", "error": [], "warning": [] }, { - "query": "from a_index | where 1 ---- numberField > 0", - "error": [], + "query": "from a_index | where booleanField > booleanField", + "error": [ + "Argument of [>] must be [number], found value [booleanField] type [boolean]", + "Argument of [>] must be [number], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | where -+-+ numberField > 0", + "query": "from a_index | where ipField > ipField", "error": [], "warning": [] }, { - "query": "from a_index | where -+-+ round(numberField) > 0", + "query": "from a_index | where numberField >= 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + -+-+ numberField > 0", + "query": "from a_index | where NOT numberField >= 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 -+-+ numberField > 0", + "query": "from a_index | where (numberField >= 0)", "error": [], "warning": [] }, { - "query": "from a_index | where +-+- numberField > 0", + "query": "from a_index | where (NOT (numberField >= 0))", "error": [], "warning": [] }, { - "query": "from a_index | where +-+- round(numberField) > 0", + "query": "from a_index | where 1 >= 0", "error": [], "warning": [] }, { - "query": "from a_index | where 1 + +-+- numberField > 0", + "query": "from a_index | where stringField >= stringField", "error": [], "warning": [] }, { - "query": "from a_index | where 1 +-+- numberField > 0", + "query": "from a_index | where numberField >= numberField", "error": [], "warning": [] }, { - "query": "from a_index | where ++++ numberField > 0", + "query": "from a_index | where dateField >= dateField", "error": [], "warning": [] }, { - "query": "from a_index | where ++++ round(numberField) > 0", - "error": [], + "query": "from a_index | where booleanField >= booleanField", + "error": [ + "Argument of [>=] must be [number], found value [booleanField] type [boolean]", + "Argument of [>=] must be [number], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | where 1 + ++++ numberField > 0", + "query": "from a_index | where ipField >= ipField", "error": [], "warning": [] }, { - "query": "from a_index | where 1 ++++ numberField > 0", + "query": "from a_index | where numberField < 0", "error": [], "warning": [] }, { - "query": "from a_index | where not not not not booleanField", + "query": "from a_index | where NOT numberField < 0", "error": [], "warning": [] }, { - "query": "from a_index | where *+ numberField", - "error": [ - "SyntaxError: extraneous input '*' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], + "query": "from a_index | where (numberField < 0)", + "error": [], "warning": [] }, { - "query": "from a_index | where /+ numberField", - "error": [ - "SyntaxError: extraneous input '/' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], + "query": "from a_index | where (NOT (numberField < 0))", + "error": [], "warning": [] }, { - "query": "from a_index | where %+ numberField", - "error": [ - "SyntaxError: extraneous input '%' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], + "query": "from a_index | where 1 < 0", + "error": [], "warning": [] }, { - "query": "from a_index | where numberField =~ 0", - "error": [ - "Argument of [=~] must be [string], found value [numberField] type [number]", - "Argument of [=~] must be [string], found value [0] type [number]" - ], + "query": "from a_index | where stringField < stringField", + "error": [], "warning": [] }, { - "query": "from a_index | where NOT numberField =~ 0", - "error": [ - "Argument of [=~] must be [string], found value [numberField] type [number]", - "Argument of [=~] must be [string], found value [0] type [number]" - ], + "query": "from a_index | where numberField < numberField", + "error": [], "warning": [] }, { - "query": "from a_index | where (numberField =~ 0)", - "error": [ - "Argument of [=~] must be [string], found value [numberField] type [number]", - "Argument of [=~] must be [string], found value [0] type [number]" - ], + "query": "from a_index | where dateField < dateField", + "error": [], "warning": [] }, { - "query": "from a_index | where (NOT (numberField =~ 0))", + "query": "from a_index | where booleanField < booleanField", "error": [ - "Argument of [=~] must be [string], found value [numberField] type [number]", - "Argument of [=~] must be [string], found value [0] type [number]" + "Argument of [<] must be [number], found value [booleanField] type [boolean]", + "Argument of [<] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | where 1 =~ 0", - "error": [ - "Argument of [=~] must be [string], found value [1] type [number]", - "Argument of [=~] must be [string], found value [0] type [number]" - ], + "query": "from a_index | where ipField < ipField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField =~ 0", - "error": [ - "Argument of [=~] must be [string], found value [0] type [number]" - ], + "query": "from a_index | where numberField <= 0", + "error": [], "warning": [] }, { - "query": "from a_index | where stringField like \"?a\"", + "query": "from a_index | where NOT numberField <= 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField NOT like \"?a\"", + "query": "from a_index | where (numberField <= 0)", "error": [], "warning": [] }, { - "query": "from a_index | where NOT stringField like \"?a\"", + "query": "from a_index | where (NOT (numberField <= 0))", "error": [], "warning": [] }, { - "query": "from a_index | where NOT stringField NOT like \"?a\"", + "query": "from a_index | where 1 <= 0", "error": [], "warning": [] }, { - "query": "from a_index | where numberField like \"?a\"", - "error": [ - "Argument of [like] must be [string], found value [numberField] type [number]" - ], + "query": "from a_index | where stringField <= stringField", + "error": [], "warning": [] }, { - "query": "from a_index | where numberField NOT like \"?a\"", - "error": [ - "Argument of [not_like] must be [string], found value [numberField] type [number]" - ], + "query": "from a_index | where numberField <= numberField", + "error": [], "warning": [] }, { - "query": "from a_index | where NOT numberField like \"?a\"", - "error": [ - "Argument of [like] must be [string], found value [numberField] type [number]" - ], + "query": "from a_index | where dateField <= dateField", + "error": [], "warning": [] }, { - "query": "from a_index | where NOT numberField NOT like \"?a\"", + "query": "from a_index | where booleanField <= booleanField", "error": [ - "Argument of [not_like] must be [string], found value [numberField] type [number]" + "Argument of [<=] must be [number], found value [booleanField] type [boolean]", + "Argument of [<=] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | where stringField rlike \"?a\"", + "query": "from a_index | where ipField <= ipField", "error": [], "warning": [] }, { - "query": "from a_index | where stringField NOT rlike \"?a\"", + "query": "from a_index | where numberField == 0", "error": [], "warning": [] }, { - "query": "from a_index | where NOT stringField rlike \"?a\"", + "query": "from a_index | where NOT numberField == 0", "error": [], "warning": [] }, { - "query": "from a_index | where NOT stringField NOT rlike \"?a\"", + "query": "from a_index | where (numberField == 0)", "error": [], "warning": [] }, { - "query": "from a_index | where numberField rlike \"?a\"", - "error": [ - "Argument of [rlike] must be [string], found value [numberField] type [number]" - ], - "warning": [] - }, - { - "query": "from a_index | where numberField NOT rlike \"?a\"", - "error": [ - "Argument of [not_rlike] must be [string], found value [numberField] type [number]" - ], - "warning": [] - }, - { - "query": "from a_index | where NOT numberField rlike \"?a\"", - "error": [ - "Argument of [rlike] must be [string], found value [numberField] type [number]" - ], + "query": "from a_index | where (NOT (numberField == 0))", + "error": [], "warning": [] }, { - "query": "from a_index | where NOT numberField NOT rlike \"?a\"", - "error": [ - "Argument of [not_rlike] must be [string], found value [numberField] type [number]" - ], + "query": "from a_index | where 1 == 0", + "error": [], "warning": [] }, { - "query": "from a_index | where cidr_match(ipField)", - "error": [ - "Error: [cidr_match] function expects at least 2 arguments, got 1." - ], + "query": "from a_index | where stringField == stringField", + "error": [], "warning": [] }, { - "query": "from a_index | eval cidr = \"172.0.0.1/30\" | where cidr_match(ipField, \"172.0.0.1/30\", cidr)", + "query": "from a_index | where numberField == numberField", "error": [], "warning": [] }, { - "query": "from a_index | where numberField IS NULL", + "query": "from a_index | where dateField == dateField", "error": [], "warning": [] }, { - "query": "from a_index | where numberField IS null", + "query": "from a_index | where booleanField == booleanField", "error": [], "warning": [] }, { - "query": "from a_index | where numberField is null", + "query": "from a_index | where ipField == ipField", "error": [], "warning": [] }, { - "query": "from a_index | where numberField is NULL", + "query": "from a_index | where numberField != 0", "error": [], "warning": [] }, { - "query": "from a_index | where numberField IS NOT NULL", + "query": "from a_index | where NOT numberField != 0", "error": [], "warning": [] }, { - "query": "from a_index | where numberField IS NOT null", + "query": "from a_index | where (numberField != 0)", "error": [], "warning": [] }, { - "query": "from a_index | where numberField IS not NULL", + "query": "from a_index | where (NOT (numberField != 0))", "error": [], "warning": [] }, { - "query": "from a_index | where numberField Is nOt NuLL", + "query": "from a_index | where 1 != 0", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS NULL", + "query": "from a_index | where stringField != stringField", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS null", + "query": "from a_index | where numberField != numberField", "error": [], "warning": [] }, { - "query": "from a_index | where dateField is null", + "query": "from a_index | where dateField != dateField", "error": [], "warning": [] }, { - "query": "from a_index | where dateField is NULL", + "query": "from a_index | where booleanField != booleanField", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS NOT NULL", + "query": "from a_index | where ipField != ipField", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS NOT null", + "query": "from a_index | where - numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS not NULL", + "query": "from a_index | where - round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where dateField Is nOt NuLL", + "query": "from a_index | where 1 + - numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField IS NULL", + "query": "from a_index | where 1 - numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField IS null", + "query": "from a_index | where - numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField is null", + "query": "from a_index | where - round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField is NULL", + "query": "from a_index | where 1 + - numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField IS NOT NULL", + "query": "from a_index | where 1 - numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField IS NOT null", + "query": "from a_index | where + numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField IS not NULL", + "query": "from a_index | where + round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField Is nOt NuLL", + "query": "from a_index | where 1 + + numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField IS NULL", + "query": "from a_index | where 1 + numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField IS null", + "query": "from a_index | where + numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField is null", + "query": "from a_index | where + round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField is NULL", + "query": "from a_index | where 1 + + numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField IS NOT NULL", + "query": "from a_index | where 1 + numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField IS NOT null", + "query": "from a_index | where not booleanField", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField IS not NULL", + "query": "from a_index | where -- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField Is nOt NuLL", + "query": "from a_index | where -- round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS NULL", + "query": "from a_index | where 1 + -- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS null", + "query": "from a_index | where 1 -- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where ipField is null", + "query": "from a_index | where -+ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where ipField is NULL", + "query": "from a_index | where -+ round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS NOT NULL", + "query": "from a_index | where 1 + -+ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS NOT null", + "query": "from a_index | where 1 -+ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS not NULL", + "query": "from a_index | where +- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where ipField Is nOt NuLL", + "query": "from a_index | where +- round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianPointField IS NULL", + "query": "from a_index | where 1 + +- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianPointField IS null", + "query": "from a_index | where 1 +- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianPointField is null", + "query": "from a_index | where ++ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianPointField is NULL", + "query": "from a_index | where ++ round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianPointField IS NOT NULL", + "query": "from a_index | where 1 + ++ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianPointField IS NOT null", + "query": "from a_index | where 1 ++ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianPointField IS not NULL", + "query": "from a_index | where not not booleanField", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianPointField Is nOt NuLL", + "query": "from a_index | where --- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianShapeField IS NULL", + "query": "from a_index | where --- round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianShapeField IS null", + "query": "from a_index | where 1 + --- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianShapeField is null", + "query": "from a_index | where 1 --- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianShapeField is NULL", + "query": "from a_index | where -+- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianShapeField IS NOT NULL", + "query": "from a_index | where -+- round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianShapeField IS NOT null", + "query": "from a_index | where 1 + -+- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianShapeField IS not NULL", + "query": "from a_index | where 1 -+- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where cartesianShapeField Is nOt NuLL", + "query": "from a_index | where +-+ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoPointField IS NULL", + "query": "from a_index | where +-+ round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoPointField IS null", + "query": "from a_index | where 1 + +-+ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoPointField is null", + "query": "from a_index | where 1 +-+ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoPointField is NULL", + "query": "from a_index | where +++ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoPointField IS NOT NULL", + "query": "from a_index | where +++ round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoPointField IS NOT null", + "query": "from a_index | where 1 + +++ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoPointField IS not NULL", + "query": "from a_index | where 1 +++ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoPointField Is nOt NuLL", + "query": "from a_index | where not not not booleanField", "error": [], "warning": [] }, { - "query": "from a_index | where geoShapeField IS NULL", + "query": "from a_index | where ---- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoShapeField IS null", + "query": "from a_index | where ---- round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoShapeField is null", + "query": "from a_index | where 1 + ---- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoShapeField is NULL", + "query": "from a_index | where 1 ---- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoShapeField IS NOT NULL", + "query": "from a_index | where -+-+ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoShapeField IS NOT null", + "query": "from a_index | where -+-+ round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoShapeField IS not NULL", + "query": "from a_index | where 1 + -+-+ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where geoShapeField Is nOt NuLL", + "query": "from a_index | where 1 -+-+ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where versionField IS NULL", + "query": "from a_index | where +-+- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where versionField IS null", + "query": "from a_index | where +-+- round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where versionField is null", + "query": "from a_index | where 1 + +-+- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where versionField is NULL", + "query": "from a_index | where 1 +-+- numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where versionField IS NOT NULL", + "query": "from a_index | where ++++ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where versionField IS NOT null", + "query": "from a_index | where ++++ round(numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | where versionField IS not NULL", + "query": "from a_index | where 1 + ++++ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where versionField Is nOt NuLL", + "query": "from a_index | where 1 ++++ numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | where stringField == \"a\" or null", + "query": "from a_index | where not not not not booleanField", "error": [], "warning": [] }, { - "query": "from a_index | eval ", + "query": "from a_index | where *+ numberField", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: extraneous input '*' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, { - "query": "from a_index | eval stringField ", - "error": [], + "query": "from a_index | where /+ numberField", + "error": [ + "SyntaxError: extraneous input '/' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + ], "warning": [] }, { - "query": "from a_index | eval b = stringField", - "error": [], + "query": "from a_index | where %+ numberField", + "error": [ + "SyntaxError: extraneous input '%' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + ], "warning": [] }, { - "query": "from a_index | eval numberField + 1", - "error": [], + "query": "from a_index | where numberField =~ 0", + "error": [ + "Argument of [=~] must be [string], found value [numberField] type [number]", + "Argument of [=~] must be [string], found value [0] type [number]" + ], "warning": [] }, { - "query": "from a_index | eval numberField + ", + "query": "from a_index | where NOT numberField =~ 0", "error": [ - "SyntaxError: no viable alternative at input 'numberField + '" + "Argument of [=~] must be [string], found value [numberField] type [number]", + "Argument of [=~] must be [string], found value [0] type [number]" ], "warning": [] }, { - "query": "from a_index | eval stringField + 1", + "query": "from a_index | where (numberField =~ 0)", "error": [ - "Argument of [+] must be [number], found value [stringField] type [string]" + "Argument of [=~] must be [string], found value [numberField] type [number]", + "Argument of [=~] must be [string], found value [0] type [number]" ], "warning": [] }, { - "query": "from a_index | eval a=b", + "query": "from a_index | where (NOT (numberField =~ 0))", "error": [ - "Unknown column [b]" + "Argument of [=~] must be [string], found value [numberField] type [number]", + "Argument of [=~] must be [string], found value [0] type [number]" ], "warning": [] }, { - "query": "from a_index | eval a=b, ", + "query": "from a_index | where 1 =~ 0", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - "Unknown column [b]" + "Argument of [=~] must be [string], found value [1] type [number]", + "Argument of [=~] must be [string], found value [0] type [number]" ], "warning": [] }, { - "query": "from a_index | eval a=round", + "query": "from a_index | eval stringField =~ 0", "error": [ - "Unknown column [round]" + "Argument of [=~] must be [string], found value [0] type [number]" ], "warning": [] }, { - "query": "from a_index | eval a=round(", - "error": [ - "SyntaxError: no viable alternative at input 'round('" - ], + "query": "from a_index | where stringField like \"?a\"", + "error": [], "warning": [] }, { - "query": "from a_index | eval a=round(numberField) ", + "query": "from a_index | where stringField NOT like \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval a=round(numberField), ", + "query": "from a_index | where NOT stringField like \"?a\"", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where NOT stringField NOT like \"?a\"", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where numberField like \"?a\"", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "Argument of [like] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval a=round(numberField) + round(numberField) ", - "error": [], + "query": "from a_index | where numberField NOT like \"?a\"", + "error": [ + "Argument of [not_like] must be [string], found value [numberField] type [number]" + ], "warning": [] }, { - "query": "from a_index | eval a=round(numberField) + round(stringField) ", + "query": "from a_index | where NOT numberField like \"?a\"", "error": [ - "Argument of [round] must be [number], found value [stringField] type [string]" + "Argument of [like] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval a=round(numberField) + round(stringField), numberField ", + "query": "from a_index | where NOT numberField NOT like \"?a\"", "error": [ - "Argument of [round] must be [number], found value [stringField] type [string]" + "Argument of [not_like] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval a=round(numberField) + round(numberField), numberField ", + "query": "from a_index | where stringField rlike \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval a=round(numberField) + round(numberField), b = numberField ", + "query": "from a_index | where stringField NOT rlike \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval a=[1, 2, 3]", + "query": "from a_index | where NOT stringField rlike \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval a=[true, false]", + "query": "from a_index | where NOT stringField NOT rlike \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval a=[\"a\", \"b\"]", - "error": [], + "query": "from a_index | where numberField rlike \"?a\"", + "error": [ + "Argument of [rlike] must be [string], found value [numberField] type [number]" + ], "warning": [] }, { - "query": "from a_index | eval a=null", - "error": [], + "query": "from a_index | where numberField NOT rlike \"?a\"", + "error": [ + "Argument of [not_rlike] must be [string], found value [numberField] type [number]" + ], "warning": [] }, { - "query": "from a_index | eval numberField IS NULL", - "error": [], + "query": "from a_index | where NOT numberField rlike \"?a\"", + "error": [ + "Argument of [rlike] must be [string], found value [numberField] type [number]" + ], "warning": [] }, { - "query": "from a_index | eval numberField IS null", + "query": "from a_index | where NOT numberField NOT rlike \"?a\"", + "error": [ + "Argument of [not_rlike] must be [string], found value [numberField] type [number]" + ], + "warning": [] + }, + { + "query": "from a_index | where cidr_match(ipField)", + "error": [ + "Error: [cidr_match] function expects at least 2 arguments, got 1." + ], + "warning": [] + }, + { + "query": "from a_index | eval cidr = \"172.0.0.1/30\" | where cidr_match(ipField, \"172.0.0.1/30\", cidr)", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField is null", + "query": "from a_index | where numberField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField is NULL", + "query": "from a_index | where numberField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField IS NOT NULL", + "query": "from a_index | where numberField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField IS NOT null", + "query": "from a_index | where numberField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField IS not NULL", + "query": "from a_index | where numberField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS NULL", + "query": "from a_index | where numberField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS null", + "query": "from a_index | where numberField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField is null", + "query": "from a_index | where numberField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField is NULL", + "query": "from a_index | where dateField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS NOT NULL", + "query": "from a_index | where dateField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS NOT null", + "query": "from a_index | where dateField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS not NULL", + "query": "from a_index | where dateField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField IS NULL", + "query": "from a_index | where dateField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField IS null", + "query": "from a_index | where dateField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField is null", + "query": "from a_index | where dateField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField is NULL", + "query": "from a_index | where dateField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField IS NOT NULL", + "query": "from a_index | where stringField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField IS NOT null", + "query": "from a_index | where stringField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField IS not NULL", + "query": "from a_index | where stringField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField IS NULL", + "query": "from a_index | where stringField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField IS null", + "query": "from a_index | where stringField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField is null", + "query": "from a_index | where stringField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField is NULL", + "query": "from a_index | where stringField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField IS NOT NULL", + "query": "from a_index | where stringField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField IS NOT null", + "query": "from a_index | where booleanField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField IS not NULL", + "query": "from a_index | where booleanField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS NULL", + "query": "from a_index | where booleanField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS null", + "query": "from a_index | where booleanField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField is null", + "query": "from a_index | where booleanField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField is NULL", + "query": "from a_index | where booleanField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS NOT NULL", + "query": "from a_index | where booleanField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS NOT null", + "query": "from a_index | where booleanField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS not NULL", + "query": "from a_index | where ipField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianPointField IS NULL", + "query": "from a_index | where ipField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianPointField IS null", + "query": "from a_index | where ipField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianPointField is null", + "query": "from a_index | where ipField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianPointField is NULL", + "query": "from a_index | where ipField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianPointField IS NOT NULL", + "query": "from a_index | where ipField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianPointField IS NOT null", + "query": "from a_index | where ipField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianPointField IS not NULL", + "query": "from a_index | where ipField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianShapeField IS NULL", + "query": "from a_index | where cartesianPointField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianShapeField IS null", + "query": "from a_index | where cartesianPointField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianShapeField is null", + "query": "from a_index | where cartesianPointField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianShapeField is NULL", + "query": "from a_index | where cartesianPointField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianShapeField IS NOT NULL", + "query": "from a_index | where cartesianPointField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianShapeField IS NOT null", + "query": "from a_index | where cartesianPointField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval cartesianShapeField IS not NULL", + "query": "from a_index | where cartesianPointField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval geoPointField IS NULL", + "query": "from a_index | where cartesianPointField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval geoPointField IS null", + "query": "from a_index | where cartesianShapeField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval geoPointField is null", + "query": "from a_index | where cartesianShapeField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval geoPointField is NULL", + "query": "from a_index | where cartesianShapeField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval geoPointField IS NOT NULL", + "query": "from a_index | where cartesianShapeField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval geoPointField IS NOT null", + "query": "from a_index | where cartesianShapeField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval geoPointField IS not NULL", + "query": "from a_index | where cartesianShapeField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval geoShapeField IS NULL", + "query": "from a_index | where cartesianShapeField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval geoShapeField IS null", + "query": "from a_index | where cartesianShapeField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval geoShapeField is null", + "query": "from a_index | where geoPointField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval geoShapeField is NULL", + "query": "from a_index | where geoPointField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval geoShapeField IS NOT NULL", + "query": "from a_index | where geoPointField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval geoShapeField IS NOT null", + "query": "from a_index | where geoPointField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval geoShapeField IS not NULL", + "query": "from a_index | where geoPointField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField IS NULL", + "query": "from a_index | where geoPointField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField IS null", + "query": "from a_index | where geoPointField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField is null", + "query": "from a_index | where geoPointField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField is NULL", + "query": "from a_index | where geoShapeField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField IS NOT NULL", + "query": "from a_index | where geoShapeField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField IS NOT null", + "query": "from a_index | where geoShapeField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField IS not NULL", + "query": "from a_index | where geoShapeField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval - numberField", + "query": "from a_index | where geoShapeField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=- numberField", + "query": "from a_index | where geoShapeField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=- round(numberField)", + "query": "from a_index | where geoShapeField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + - numberField", + "query": "from a_index | where geoShapeField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 - numberField", + "query": "from a_index | where versionField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval - numberField", + "query": "from a_index | where versionField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=- numberField", + "query": "from a_index | where versionField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=- round(numberField)", + "query": "from a_index | where versionField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + - numberField", + "query": "from a_index | where versionField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 - numberField", + "query": "from a_index | where versionField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval + numberField", + "query": "from a_index | where versionField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+ numberField", + "query": "from a_index | where versionField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+ round(numberField)", + "query": "from a_index | where stringField == \"a\" or null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + + numberField", - "error": [], + "query": "from a_index | eval ", + "error": [ + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + ], "warning": [] }, { - "query": "from a_index | eval 1 + numberField", + "query": "from a_index | eval stringField ", "error": [], "warning": [] }, { - "query": "from a_index | eval + numberField", + "query": "from a_index | eval b = stringField", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+ numberField", + "query": "from a_index | eval numberField + 1", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+ round(numberField)", - "error": [], + "query": "from a_index | eval numberField + ", + "error": [ + "SyntaxError: no viable alternative at input 'numberField + '" + ], "warning": [] }, { - "query": "from a_index | eval 1 + + numberField", - "error": [], + "query": "from a_index | eval stringField + 1", + "error": [ + "Argument of [+] must be [number], found value [stringField] type [string]" + ], "warning": [] }, { - "query": "from a_index | eval 1 + numberField", - "error": [], + "query": "from a_index | eval a=b", + "error": [ + "Unknown column [b]" + ], "warning": [] }, { - "query": "from a_index | eval not booleanField", - "error": [], + "query": "from a_index | eval a=b, ", + "error": [ + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "Unknown column [b]" + ], "warning": [] }, { - "query": "from a_index | eval -- numberField", - "error": [], + "query": "from a_index | eval a=round", + "error": [ + "Unknown column [round]" + ], "warning": [] }, { - "query": "from a_index | eval a=-- numberField", - "error": [], + "query": "from a_index | eval a=round(", + "error": [ + "SyntaxError: no viable alternative at input 'round('" + ], "warning": [] }, { - "query": "from a_index | eval a=-- round(numberField)", + "query": "from a_index | eval a=round(numberField) ", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + -- numberField", - "error": [], + "query": "from a_index | eval a=round(numberField), ", + "error": [ + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + ], "warning": [] }, { - "query": "from a_index | eval 1 -- numberField", + "query": "from a_index | eval a=round(numberField) + round(numberField) ", "error": [], "warning": [] }, { - "query": "from a_index | eval -+ numberField", - "error": [], + "query": "from a_index | eval a=round(numberField) + round(stringField) ", + "error": [ + "Argument of [round] must be [number], found value [stringField] type [string]" + ], "warning": [] }, { - "query": "from a_index | eval a=-+ numberField", - "error": [], + "query": "from a_index | eval a=round(numberField) + round(stringField), numberField ", + "error": [ + "Argument of [round] must be [number], found value [stringField] type [string]" + ], "warning": [] }, { - "query": "from a_index | eval a=-+ round(numberField)", + "query": "from a_index | eval a=round(numberField) + round(numberField), numberField ", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + -+ numberField", + "query": "from a_index | eval a=round(numberField) + round(numberField), b = numberField ", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 -+ numberField", + "query": "from a_index | eval a=[1, 2, 3]", "error": [], "warning": [] }, { - "query": "from a_index | eval +- numberField", + "query": "from a_index | eval a=[true, false]", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+- numberField", + "query": "from a_index | eval a=[\"a\", \"b\"]", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+- round(numberField)", + "query": "from a_index | eval a=null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + +- numberField", + "query": "from a_index | eval numberField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 +- numberField", + "query": "from a_index | eval numberField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval ++ numberField", + "query": "from a_index | eval numberField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=++ numberField", + "query": "from a_index | eval numberField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=++ round(numberField)", + "query": "from a_index | eval numberField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + ++ numberField", + "query": "from a_index | eval numberField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 ++ numberField", + "query": "from a_index | eval numberField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval not not booleanField", + "query": "from a_index | eval dateField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval --- numberField", + "query": "from a_index | eval dateField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=--- numberField", + "query": "from a_index | eval dateField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=--- round(numberField)", + "query": "from a_index | eval dateField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + --- numberField", + "query": "from a_index | eval dateField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 --- numberField", + "query": "from a_index | eval dateField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval -+- numberField", + "query": "from a_index | eval dateField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=-+- numberField", + "query": "from a_index | eval stringField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=-+- round(numberField)", + "query": "from a_index | eval stringField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + -+- numberField", + "query": "from a_index | eval stringField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 -+- numberField", + "query": "from a_index | eval stringField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval +-+ numberField", + "query": "from a_index | eval stringField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+-+ numberField", + "query": "from a_index | eval stringField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+-+ round(numberField)", + "query": "from a_index | eval stringField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + +-+ numberField", + "query": "from a_index | eval booleanField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 +-+ numberField", + "query": "from a_index | eval booleanField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval +++ numberField", + "query": "from a_index | eval booleanField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+++ numberField", + "query": "from a_index | eval booleanField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+++ round(numberField)", + "query": "from a_index | eval booleanField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + +++ numberField", + "query": "from a_index | eval booleanField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 +++ numberField", + "query": "from a_index | eval booleanField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval not not not booleanField", + "query": "from a_index | eval ipField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval ---- numberField", + "query": "from a_index | eval ipField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=---- numberField", + "query": "from a_index | eval ipField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=---- round(numberField)", + "query": "from a_index | eval ipField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + ---- numberField", + "query": "from a_index | eval ipField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 ---- numberField", + "query": "from a_index | eval ipField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval -+-+ numberField", + "query": "from a_index | eval ipField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=-+-+ numberField", + "query": "from a_index | eval cartesianPointField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=-+-+ round(numberField)", + "query": "from a_index | eval cartesianPointField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + -+-+ numberField", + "query": "from a_index | eval cartesianPointField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 -+-+ numberField", + "query": "from a_index | eval cartesianPointField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval +-+- numberField", + "query": "from a_index | eval cartesianPointField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+-+- numberField", + "query": "from a_index | eval cartesianPointField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=+-+- round(numberField)", + "query": "from a_index | eval cartesianPointField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + +-+- numberField", + "query": "from a_index | eval cartesianShapeField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 +-+- numberField", + "query": "from a_index | eval cartesianShapeField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval ++++ numberField", + "query": "from a_index | eval cartesianShapeField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval a=++++ numberField", + "query": "from a_index | eval cartesianShapeField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval a=++++ round(numberField)", + "query": "from a_index | eval cartesianShapeField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + ++++ numberField", + "query": "from a_index | eval cartesianShapeField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 ++++ numberField", + "query": "from a_index | eval cartesianShapeField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval not not not not booleanField", + "query": "from a_index | eval geoPointField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval *+ numberField", - "error": [ - "SyntaxError: extraneous input '*' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], + "query": "from a_index | eval geoPointField IS null", + "error": [], "warning": [] }, { - "query": "from a_index | eval /+ numberField", - "error": [ - "SyntaxError: extraneous input '/' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], + "query": "from a_index | eval geoPointField is null", + "error": [], "warning": [] }, { - "query": "from a_index | eval %+ numberField", - "error": [ - "SyntaxError: extraneous input '%' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], + "query": "from a_index | eval geoPointField is NULL", + "error": [], "warning": [] }, { - "query": "from a_index | eval log10(-1)", + "query": "from a_index | eval geoPointField IS NOT NULL", "error": [], - "warning": [ - "Log of a negative number results in null: -1" - ] + "warning": [] }, { - "query": "from a_index | eval log(-1)", + "query": "from a_index | eval geoPointField IS NOT null", "error": [], - "warning": [ - "Log of a negative number results in null: -1" - ] + "warning": [] }, { - "query": "from a_index | eval log(-1, 20)", + "query": "from a_index | eval geoPointField IS not NULL", "error": [], - "warning": [ - "Log of a negative number results in null: -1" - ] + "warning": [] }, { - "query": "from a_index | eval log(-1, -20)", + "query": "from a_index | eval geoShapeField IS NULL", "error": [], - "warning": [ - "Log of a negative number results in null: -1", - "Log of a negative number results in null: -20" - ] + "warning": [] }, { - "query": "from a_index | eval var0 = log(-1, -20)", + "query": "from a_index | eval geoShapeField IS null", "error": [], - "warning": [ - "Log of a negative number results in null: -1", - "Log of a negative number results in null: -20" - ] + "warning": [] }, { - "query": "from a_index | eval numberField > 0", + "query": "from a_index | eval geoShapeField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval NOT numberField > 0", + "query": "from a_index | eval geoShapeField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval (numberField > 0)", + "query": "from a_index | eval geoShapeField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval (NOT (numberField > 0))", + "query": "from a_index | eval geoShapeField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 > 0", + "query": "from a_index | eval geoShapeField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField > stringField", + "query": "from a_index | eval versionField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField > numberField", + "query": "from a_index | eval versionField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField > dateField", + "query": "from a_index | eval versionField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField > booleanField", - "error": [ - "Argument of [>] must be [number], found value [booleanField] type [boolean]", - "Argument of [>] must be [number], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval versionField is NULL", + "error": [], "warning": [] }, { - "query": "from a_index | eval ipField > ipField", + "query": "from a_index | eval versionField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField > stringField", - "error": [ - "Argument of [>] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval versionField IS NOT null", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField > numberField", - "error": [ - "Argument of [>] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval versionField IS not NULL", + "error": [], "warning": [] }, { - "query": "from a_index | eval numberField > \"2022\"", - "error": [ - "Argument of [>] must be [number], found value [\"2022\"] type [string]" - ], + "query": "from a_index | eval - numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval dateField > stringField", - "error": [ - "Argument of [>] must be [string], found value [dateField] type [date]" - ], + "query": "from a_index | eval a=- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField > dateField", - "error": [ - "Argument of [>] must be [string], found value [dateField] type [date]" - ], + "query": "from a_index | eval a=- round(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField > 0", - "error": [ - "Argument of [>] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval 1 + - numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField > now()", - "error": [ - "Argument of [>] must be [string], found value [now()] type [date]" - ], + "query": "from a_index | eval 1 - numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval dateField > \"2022\"", + "query": "from a_index | eval - numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval \"2022\" > dateField", + "query": "from a_index | eval a=- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField > \"1.2.3\"", + "query": "from a_index | eval a=- round(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval \"1.2.3\" > versionField", + "query": "from a_index | eval 1 + - numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField > \"true\"", - "error": [ - "Argument of [>] must be [string], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval 1 - numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval \"true\" > booleanField", - "error": [ - "Argument of [>] must be [string], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval + numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval ipField > \"136.36.3.205\"", + "query": "from a_index | eval a=+ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval \"136.36.3.205\" > ipField", + "query": "from a_index | eval a=+ round(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField >= 0", + "query": "from a_index | eval 1 + + numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval NOT numberField >= 0", + "query": "from a_index | eval 1 + numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval (numberField >= 0)", + "query": "from a_index | eval + numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval (NOT (numberField >= 0))", + "query": "from a_index | eval a=+ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 >= 0", + "query": "from a_index | eval a=+ round(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField >= stringField", + "query": "from a_index | eval 1 + + numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField >= numberField", + "query": "from a_index | eval 1 + numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField >= dateField", + "query": "from a_index | eval not booleanField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField >= booleanField", - "error": [ - "Argument of [>=] must be [number], found value [booleanField] type [boolean]", - "Argument of [>=] must be [number], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval -- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval ipField >= ipField", + "query": "from a_index | eval a=-- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField >= stringField", - "error": [ - "Argument of [>=] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval a=-- round(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField >= numberField", - "error": [ - "Argument of [>=] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval 1 + -- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval numberField >= \"2022\"", - "error": [ - "Argument of [>=] must be [number], found value [\"2022\"] type [string]" - ], + "query": "from a_index | eval 1 -- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval dateField >= stringField", - "error": [ - "Argument of [>=] must be [string], found value [dateField] type [date]" - ], + "query": "from a_index | eval -+ numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField >= dateField", - "error": [ - "Argument of [>=] must be [string], found value [dateField] type [date]" - ], + "query": "from a_index | eval a=-+ numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField >= 0", - "error": [ - "Argument of [>=] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval a=-+ round(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField >= now()", - "error": [ - "Argument of [>=] must be [string], found value [now()] type [date]" - ], + "query": "from a_index | eval 1 + -+ numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval dateField >= \"2022\"", + "query": "from a_index | eval 1 -+ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval \"2022\" >= dateField", + "query": "from a_index | eval +- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField >= \"1.2.3\"", + "query": "from a_index | eval a=+- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval \"1.2.3\" >= versionField", + "query": "from a_index | eval a=+- round(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField >= \"true\"", - "error": [ - "Argument of [>=] must be [string], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval 1 + +- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval \"true\" >= booleanField", - "error": [ - "Argument of [>=] must be [string], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval 1 +- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval ipField >= \"136.36.3.205\"", + "query": "from a_index | eval ++ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval \"136.36.3.205\" >= ipField", + "query": "from a_index | eval a=++ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField < 0", + "query": "from a_index | eval a=++ round(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval NOT numberField < 0", + "query": "from a_index | eval 1 + ++ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval (numberField < 0)", + "query": "from a_index | eval 1 ++ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval (NOT (numberField < 0))", + "query": "from a_index | eval not not booleanField", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 < 0", + "query": "from a_index | eval --- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField < stringField", + "query": "from a_index | eval a=--- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField < numberField", + "query": "from a_index | eval a=--- round(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField < dateField", + "query": "from a_index | eval 1 + --- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField < booleanField", - "error": [ - "Argument of [<] must be [number], found value [booleanField] type [boolean]", - "Argument of [<] must be [number], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval 1 --- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval ipField < ipField", + "query": "from a_index | eval -+- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField < stringField", - "error": [ - "Argument of [<] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval a=-+- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField < numberField", - "error": [ - "Argument of [<] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval a=-+- round(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval numberField < \"2022\"", - "error": [ - "Argument of [<] must be [number], found value [\"2022\"] type [string]" - ], + "query": "from a_index | eval 1 + -+- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval dateField < stringField", - "error": [ - "Argument of [<] must be [string], found value [dateField] type [date]" - ], + "query": "from a_index | eval 1 -+- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField < dateField", - "error": [ - "Argument of [<] must be [string], found value [dateField] type [date]" - ], + "query": "from a_index | eval +-+ numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField < 0", - "error": [ - "Argument of [<] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval a=+-+ numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField < now()", - "error": [ - "Argument of [<] must be [string], found value [now()] type [date]" - ], + "query": "from a_index | eval a=+-+ round(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval dateField < \"2022\"", + "query": "from a_index | eval 1 + +-+ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval \"2022\" < dateField", + "query": "from a_index | eval 1 +-+ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField < \"1.2.3\"", + "query": "from a_index | eval +++ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval \"1.2.3\" < versionField", + "query": "from a_index | eval a=+++ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField < \"true\"", - "error": [ - "Argument of [<] must be [string], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval a=+++ round(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval \"true\" < booleanField", - "error": [ - "Argument of [<] must be [string], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval 1 + +++ numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval ipField < \"136.36.3.205\"", + "query": "from a_index | eval 1 +++ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval \"136.36.3.205\" < ipField", + "query": "from a_index | eval not not not booleanField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField <= 0", + "query": "from a_index | eval ---- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval NOT numberField <= 0", + "query": "from a_index | eval a=---- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval (numberField <= 0)", + "query": "from a_index | eval a=---- round(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval (NOT (numberField <= 0))", + "query": "from a_index | eval 1 + ---- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 <= 0", + "query": "from a_index | eval 1 ---- numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField <= stringField", + "query": "from a_index | eval -+-+ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField <= numberField", + "query": "from a_index | eval a=-+-+ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField <= dateField", + "query": "from a_index | eval a=-+-+ round(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField <= booleanField", - "error": [ - "Argument of [<=] must be [number], found value [booleanField] type [boolean]", - "Argument of [<=] must be [number], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval 1 + -+-+ numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval ipField <= ipField", + "query": "from a_index | eval 1 -+-+ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField <= stringField", - "error": [ - "Argument of [<=] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval +-+- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField <= numberField", - "error": [ - "Argument of [<=] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval a=+-+- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval numberField <= \"2022\"", - "error": [ - "Argument of [<=] must be [number], found value [\"2022\"] type [string]" - ], + "query": "from a_index | eval a=+-+- round(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval dateField <= stringField", - "error": [ - "Argument of [<=] must be [string], found value [dateField] type [date]" - ], + "query": "from a_index | eval 1 + +-+- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField <= dateField", - "error": [ - "Argument of [<=] must be [string], found value [dateField] type [date]" - ], + "query": "from a_index | eval 1 +-+- numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField <= 0", - "error": [ - "Argument of [<=] must be [number], found value [stringField] type [string]" - ], + "query": "from a_index | eval ++++ numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField <= now()", - "error": [ - "Argument of [<=] must be [string], found value [now()] type [date]" - ], + "query": "from a_index | eval a=++++ numberField", + "error": [], "warning": [] }, { - "query": "from a_index | eval dateField <= \"2022\"", + "query": "from a_index | eval a=++++ round(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval \"2022\" <= dateField", + "query": "from a_index | eval 1 + ++++ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField <= \"1.2.3\"", + "query": "from a_index | eval 1 ++++ numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval \"1.2.3\" <= versionField", + "query": "from a_index | eval not not not not booleanField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField <= \"true\"", + "query": "from a_index | eval *+ numberField", "error": [ - "Argument of [<=] must be [string], found value [booleanField] type [boolean]" + "SyntaxError: extraneous input '*' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, { - "query": "from a_index | eval \"true\" <= booleanField", + "query": "from a_index | eval /+ numberField", "error": [ - "Argument of [<=] must be [string], found value [booleanField] type [boolean]" + "SyntaxError: extraneous input '/' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, { - "query": "from a_index | eval ipField <= \"136.36.3.205\"", - "error": [], + "query": "from a_index | eval %+ numberField", + "error": [ + "SyntaxError: extraneous input '%' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + ], "warning": [] }, { - "query": "from a_index | eval \"136.36.3.205\" <= ipField", + "query": "from a_index | eval log10(-1)", "error": [], - "warning": [] + "warning": [ + "Log of a negative number results in null: -1" + ] }, { - "query": "from a_index | eval numberField == 0", + "query": "from a_index | eval log(-1)", + "error": [], + "warning": [ + "Log of a negative number results in null: -1" + ] + }, + { + "query": "from a_index | eval log(-1, 20)", + "error": [], + "warning": [ + "Log of a negative number results in null: -1" + ] + }, + { + "query": "from a_index | eval log(-1, -20)", + "error": [], + "warning": [ + "Log of a negative number results in null: -1", + "Log of a negative number results in null: -20" + ] + }, + { + "query": "from a_index | eval var0 = log(-1, -20)", + "error": [], + "warning": [ + "Log of a negative number results in null: -1", + "Log of a negative number results in null: -20" + ] + }, + { + "query": "from a_index | eval numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | eval NOT numberField == 0", + "query": "from a_index | eval NOT numberField > 0", "error": [], "warning": [] }, { - "query": "from a_index | eval (numberField == 0)", + "query": "from a_index | eval (numberField > 0)", "error": [], "warning": [] }, { - "query": "from a_index | eval (NOT (numberField == 0))", + "query": "from a_index | eval (NOT (numberField > 0))", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 == 0", + "query": "from a_index | eval 1 > 0", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField == stringField", + "query": "from a_index | eval stringField > stringField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField == numberField", + "query": "from a_index | eval numberField > numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField == dateField", + "query": "from a_index | eval dateField > dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField == booleanField", - "error": [], + "query": "from a_index | eval booleanField > booleanField", + "error": [ + "Argument of [>] must be [number], found value [booleanField] type [boolean]", + "Argument of [>] must be [number], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | eval ipField == ipField", + "query": "from a_index | eval ipField > ipField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField == stringField", + "query": "from a_index | eval numberField > stringField", "error": [ - "Argument of [==] must be [number], found value [stringField] type [string]" + "Argument of [>] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval stringField == numberField", + "query": "from a_index | eval stringField > numberField", "error": [ - "Argument of [==] must be [number], found value [stringField] type [string]" + "Argument of [>] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval numberField == \"2022\"", + "query": "from a_index | eval numberField > \"2022\"", "error": [ - "Argument of [==] must be [number], found value [\"2022\"] type [string]" + "Argument of [>] must be [number], found value [\"2022\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval dateField == stringField", + "query": "from a_index | eval dateField > stringField", "error": [ - "Argument of [==] must be [string], found value [dateField] type [date]" + "Argument of [>] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval stringField == dateField", + "query": "from a_index | eval stringField > dateField", "error": [ - "Argument of [==] must be [string], found value [dateField] type [date]" + "Argument of [>] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval stringField == 0", + "query": "from a_index | eval stringField > 0", "error": [ - "Argument of [==] must be [number], found value [stringField] type [string]" + "Argument of [>] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval stringField == now()", + "query": "from a_index | eval stringField > now()", "error": [ - "Argument of [==] must be [string], found value [now()] type [date]" + "Argument of [>] must be [string], found value [now()] type [date]" ], "warning": [] }, { - "query": "from a_index | eval dateField == \"2022\"", + "query": "from a_index | eval dateField > \"2022\"", "error": [], "warning": [] }, { - "query": "from a_index | eval \"2022\" == dateField", + "query": "from a_index | eval \"2022\" > dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField == \"1.2.3\"", + "query": "from a_index | eval versionField > \"1.2.3\"", "error": [], "warning": [] }, { - "query": "from a_index | eval \"1.2.3\" == versionField", + "query": "from a_index | eval \"1.2.3\" > versionField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField == \"true\"", - "error": [], + "query": "from a_index | eval booleanField > \"true\"", + "error": [ + "Argument of [>] must be [string], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | eval \"true\" == booleanField", - "error": [], + "query": "from a_index | eval \"true\" > booleanField", + "error": [ + "Argument of [>] must be [string], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | eval ipField == \"136.36.3.205\"", + "query": "from a_index | eval ipField > \"136.36.3.205\"", "error": [], "warning": [] }, { - "query": "from a_index | eval \"136.36.3.205\" == ipField", + "query": "from a_index | eval \"136.36.3.205\" > ipField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField != 0", + "query": "from a_index | eval numberField >= 0", "error": [], "warning": [] }, { - "query": "from a_index | eval NOT numberField != 0", + "query": "from a_index | eval NOT numberField >= 0", "error": [], "warning": [] }, { - "query": "from a_index | eval (numberField != 0)", + "query": "from a_index | eval (numberField >= 0)", "error": [], "warning": [] }, { - "query": "from a_index | eval (NOT (numberField != 0))", + "query": "from a_index | eval (NOT (numberField >= 0))", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 != 0", + "query": "from a_index | eval 1 >= 0", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField != stringField", + "query": "from a_index | eval stringField >= stringField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField != numberField", + "query": "from a_index | eval numberField >= numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField != dateField", + "query": "from a_index | eval dateField >= dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField != booleanField", - "error": [], + "query": "from a_index | eval booleanField >= booleanField", + "error": [ + "Argument of [>=] must be [number], found value [booleanField] type [boolean]", + "Argument of [>=] must be [number], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | eval ipField != ipField", + "query": "from a_index | eval ipField >= ipField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField != stringField", + "query": "from a_index | eval numberField >= stringField", "error": [ - "Argument of [!=] must be [number], found value [stringField] type [string]" + "Argument of [>=] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval stringField != numberField", + "query": "from a_index | eval stringField >= numberField", "error": [ - "Argument of [!=] must be [number], found value [stringField] type [string]" + "Argument of [>=] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval numberField != \"2022\"", + "query": "from a_index | eval numberField >= \"2022\"", "error": [ - "Argument of [!=] must be [number], found value [\"2022\"] type [string]" + "Argument of [>=] must be [number], found value [\"2022\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval dateField != stringField", + "query": "from a_index | eval dateField >= stringField", "error": [ - "Argument of [!=] must be [string], found value [dateField] type [date]" + "Argument of [>=] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval stringField != dateField", + "query": "from a_index | eval stringField >= dateField", "error": [ - "Argument of [!=] must be [string], found value [dateField] type [date]" + "Argument of [>=] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval stringField != 0", + "query": "from a_index | eval stringField >= 0", "error": [ - "Argument of [!=] must be [number], found value [stringField] type [string]" + "Argument of [>=] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval stringField != now()", + "query": "from a_index | eval stringField >= now()", "error": [ - "Argument of [!=] must be [string], found value [now()] type [date]" + "Argument of [>=] must be [string], found value [now()] type [date]" ], "warning": [] }, { - "query": "from a_index | eval dateField != \"2022\"", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval \"2022\" != dateField", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval versionField != \"1.2.3\"", + "query": "from a_index | eval dateField >= \"2022\"", "error": [], "warning": [] }, { - "query": "from a_index | eval \"1.2.3\" != versionField", + "query": "from a_index | eval \"2022\" >= dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField != \"true\"", + "query": "from a_index | eval versionField >= \"1.2.3\"", "error": [], "warning": [] }, { - "query": "from a_index | eval \"true\" != booleanField", + "query": "from a_index | eval \"1.2.3\" >= versionField", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField != \"136.36.3.205\"", - "error": [], + "query": "from a_index | eval booleanField >= \"true\"", + "error": [ + "Argument of [>=] must be [string], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | eval \"136.36.3.205\" != ipField", - "error": [], + "query": "from a_index | eval \"true\" >= booleanField", + "error": [ + "Argument of [>=] must be [string], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | eval versionField in (\"1.2.3\", \"4.5.6\", to_version(\"2.3.2\"))", + "query": "from a_index | eval ipField >= \"136.36.3.205\"", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField in (\"2023-12-12\", \"2024-12-12\", date_parse(\"yyyy-MM-dd\", \"2025-12-12\"))", + "query": "from a_index | eval \"136.36.3.205\" >= ipField", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField in (\"true\", \"false\", false)", + "query": "from a_index | eval numberField < 0", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField in (\"136.36.3.205\", \"136.36.3.206\", to_ip(\"136.36.3.207\"))", + "query": "from a_index | eval NOT numberField < 0", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField + 1", + "query": "from a_index | eval (numberField < 0)", "error": [], "warning": [] }, { - "query": "from a_index | eval (numberField + 1)", + "query": "from a_index | eval (NOT (numberField < 0))", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 + 1", + "query": "from a_index | eval 1 < 0", "error": [], "warning": [] }, { - "query": "from a_index | eval now() + now()", - "error": [ - "Argument of [+] must be [time_literal], found value [now()] type [date]" - ], - "warning": [] - }, - { - "query": "from a_index | eval 1 + \"1\"", - "error": [ - "Argument of [+] must be [number], found value [\"1\"] type [string]" - ], - "warning": [] - }, - { - "query": "from a_index | eval \"1\" + 1", - "error": [ - "Argument of [+] must be [number], found value [\"1\"] type [string]" - ], - "warning": [] - }, - { - "query": "from a_index | eval numberField - 1", + "query": "from a_index | eval stringField < stringField", "error": [], "warning": [] }, { - "query": "from a_index | eval (numberField - 1)", + "query": "from a_index | eval numberField < numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 - 1", + "query": "from a_index | eval dateField < dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval now() - now()", + "query": "from a_index | eval booleanField < booleanField", "error": [ - "Argument of [-] must be [time_literal], found value [now()] type [date]" + "Argument of [<] must be [number], found value [booleanField] type [boolean]", + "Argument of [<] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval 1 - \"1\"", - "error": [ - "Argument of [-] must be [number], found value [\"1\"] type [string]" - ], + "query": "from a_index | eval ipField < ipField", + "error": [], "warning": [] }, { - "query": "from a_index | eval \"1\" - 1", + "query": "from a_index | eval numberField < stringField", "error": [ - "Argument of [-] must be [number], found value [\"1\"] type [string]" + "Argument of [<] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval numberField * 1", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval (numberField * 1)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval 1 * 1", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval now() * now()", + "query": "from a_index | eval stringField < numberField", "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [now()] type [date]" + "Argument of [<] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval 1 * \"1\"", + "query": "from a_index | eval numberField < \"2022\"", "error": [ - "Argument of [*] must be [number], found value [\"1\"] type [string]" + "Argument of [<] must be [number], found value [\"2022\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval \"1\" * 1", + "query": "from a_index | eval dateField < stringField", "error": [ - "Argument of [*] must be [number], found value [\"1\"] type [string]" + "Argument of [<] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval numberField / 1", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval (numberField / 1)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval 1 / 1", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval now() / now()", + "query": "from a_index | eval stringField < dateField", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [now()] type [date]" + "Argument of [<] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval 1 / \"1\"", + "query": "from a_index | eval stringField < 0", "error": [ - "Argument of [/] must be [number], found value [\"1\"] type [string]" + "Argument of [<] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval \"1\" / 1", + "query": "from a_index | eval stringField < now()", "error": [ - "Argument of [/] must be [number], found value [\"1\"] type [string]" + "Argument of [<] must be [string], found value [now()] type [date]" ], "warning": [] }, { - "query": "from a_index | eval numberField % 1", + "query": "from a_index | eval dateField < \"2022\"", "error": [], "warning": [] }, { - "query": "from a_index | eval (numberField % 1)", + "query": "from a_index | eval \"2022\" < dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 % 1", + "query": "from a_index | eval versionField < \"1.2.3\"", "error": [], "warning": [] }, { - "query": "from a_index | eval now() % now()", - "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [now()] type [date]" - ], + "query": "from a_index | eval \"1.2.3\" < versionField", + "error": [], "warning": [] }, { - "query": "from a_index | eval 1 % \"1\"", + "query": "from a_index | eval booleanField < \"true\"", "error": [ - "Argument of [%] must be [number], found value [\"1\"] type [string]" + "Argument of [<] must be [string], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval \"1\" % 1", + "query": "from a_index | eval \"true\" < booleanField", "error": [ - "Argument of [%] must be [number], found value [\"1\"] type [string]" + "Argument of [<] must be [string], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval 1/0", + "query": "from a_index | eval ipField < \"136.36.3.205\"", "error": [], - "warning": [ - "Cannot divide by zero: 1/0" - ] + "warning": [] }, { - "query": "from a_index | eval var = 1/0", + "query": "from a_index | eval \"136.36.3.205\" < ipField", "error": [], - "warning": [ - "Cannot divide by zero: 1/0" - ] + "warning": [] }, { - "query": "from a_index | eval 1 + 1/0", + "query": "from a_index | eval numberField <= 0", "error": [], - "warning": [ - "Cannot divide by zero: 1/0" - ] + "warning": [] }, { - "query": "from a_index | eval 1%0", + "query": "from a_index | eval NOT numberField <= 0", "error": [], - "warning": [ - "Module by zero can return null value: 1%0" - ] + "warning": [] }, { - "query": "from a_index | eval var = 1%0", + "query": "from a_index | eval (numberField <= 0)", "error": [], - "warning": [ - "Module by zero can return null value: 1%0" - ] + "warning": [] }, { - "query": "from a_index | eval 1 + 1%0", + "query": "from a_index | eval (NOT (numberField <= 0))", "error": [], - "warning": [ - "Module by zero can return null value: 1%0" - ] + "warning": [] }, { - "query": "from a_index | eval stringField like \"?a\"", + "query": "from a_index | eval 1 <= 0", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField NOT like \"?a\"", + "query": "from a_index | eval stringField <= stringField", "error": [], "warning": [] }, { - "query": "from a_index | eval NOT stringField like \"?a\"", + "query": "from a_index | eval numberField <= numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval NOT stringField NOT like \"?a\"", + "query": "from a_index | eval dateField <= dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField like \"?a\"", + "query": "from a_index | eval booleanField <= booleanField", "error": [ - "Argument of [like] must be [string], found value [numberField] type [number]" + "Argument of [<=] must be [number], found value [booleanField] type [boolean]", + "Argument of [<=] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval numberField NOT like \"?a\"", - "error": [ - "Argument of [not_like] must be [string], found value [numberField] type [number]" - ], + "query": "from a_index | eval ipField <= ipField", + "error": [], "warning": [] }, { - "query": "from a_index | eval NOT numberField like \"?a\"", + "query": "from a_index | eval numberField <= stringField", "error": [ - "Argument of [like] must be [string], found value [numberField] type [number]" + "Argument of [<=] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval NOT numberField NOT like \"?a\"", + "query": "from a_index | eval stringField <= numberField", "error": [ - "Argument of [not_like] must be [string], found value [numberField] type [number]" + "Argument of [<=] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval stringField rlike \"?a\"", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval stringField NOT rlike \"?a\"", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval NOT stringField rlike \"?a\"", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval NOT stringField NOT rlike \"?a\"", - "error": [], + "query": "from a_index | eval numberField <= \"2022\"", + "error": [ + "Argument of [<=] must be [number], found value [\"2022\"] type [string]" + ], "warning": [] }, { - "query": "from a_index | eval numberField rlike \"?a\"", + "query": "from a_index | eval dateField <= stringField", "error": [ - "Argument of [rlike] must be [string], found value [numberField] type [number]" + "Argument of [<=] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval numberField NOT rlike \"?a\"", + "query": "from a_index | eval stringField <= dateField", "error": [ - "Argument of [not_rlike] must be [string], found value [numberField] type [number]" + "Argument of [<=] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval NOT numberField rlike \"?a\"", + "query": "from a_index | eval stringField <= 0", "error": [ - "Argument of [rlike] must be [string], found value [numberField] type [number]" + "Argument of [<=] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval NOT numberField NOT rlike \"?a\"", + "query": "from a_index | eval stringField <= now()", "error": [ - "Argument of [not_rlike] must be [string], found value [numberField] type [number]" + "Argument of [<=] must be [string], found value [now()] type [date]" ], "warning": [] }, { - "query": "from a_index | eval 1 in (1, 2, 3)", + "query": "from a_index | eval dateField <= \"2022\"", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField in (1, 2, 3)", + "query": "from a_index | eval \"2022\" <= dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField not in (1, 2, 3)", + "query": "from a_index | eval versionField <= \"1.2.3\"", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField not in (1, 2, 3, numberField)", + "query": "from a_index | eval \"1.2.3\" <= versionField", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 in (1, 2, 3, round(numberField))", - "error": [], + "query": "from a_index | eval booleanField <= \"true\"", + "error": [ + "Argument of [<=] must be [string], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | eval \"a\" in (\"a\", \"b\", \"c\")", - "error": [], + "query": "from a_index | eval \"true\" <= booleanField", + "error": [ + "Argument of [<=] must be [string], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | eval stringField in (\"a\", \"b\", \"c\")", + "query": "from a_index | eval ipField <= \"136.36.3.205\"", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField not in (\"a\", \"b\", \"c\")", + "query": "from a_index | eval \"136.36.3.205\" <= ipField", "error": [], "warning": [] }, { - "query": "from a_index | eval stringField not in (\"a\", \"b\", \"c\", stringField)", + "query": "from a_index | eval numberField == 0", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 in (\"a\", \"b\", \"c\")", + "query": "from a_index | eval NOT numberField == 0", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField in (\"a\", \"b\", \"c\")", + "query": "from a_index | eval (numberField == 0)", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField not in (\"a\", \"b\", \"c\")", + "query": "from a_index | eval (NOT (numberField == 0))", "error": [], "warning": [] }, { - "query": "from a_index | eval numberField not in (1, 2, 3, stringField)", + "query": "from a_index | eval 1 == 0", "error": [], "warning": [] }, { - "query": "from a_index | eval avg(numberField)", - "error": [ - "EVAL does not support function avg" - ], + "query": "from a_index | eval stringField == stringField", + "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField) | eval `avg(numberField)` + 1", + "query": "from a_index | eval numberField == numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval not", - "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - "Error: [not] function expects exactly one argument, got 0." - ], + "query": "from a_index | eval dateField == dateField", + "error": [], "warning": [] }, { - "query": "from a_index | eval in", - "error": [ - "SyntaxError: mismatched input 'in' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" - ], + "query": "from a_index | eval booleanField == booleanField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField in stringField", - "error": [ - "SyntaxError: missing '(' at 'stringField'", - "SyntaxError: mismatched input '' expecting {',', ')'}" - ], + "query": "from a_index | eval ipField == ipField", + "error": [], "warning": [] }, { - "query": "from a_index | eval stringField in stringField)", + "query": "from a_index | eval numberField == stringField", "error": [ - "SyntaxError: missing '(' at 'stringField'", - "Error: [in] function expects exactly 2 arguments, got 1." + "Argument of [==] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval stringField not in stringField", + "query": "from a_index | eval stringField == numberField", "error": [ - "SyntaxError: missing '(' at 'stringField'", - "SyntaxError: mismatched input '' expecting {',', ')'}" + "Argument of [==] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval mv_sort([\"a\", \"b\"], \"bogus\")", - "error": [], - "warning": [ - "Invalid option [\"bogus\"] for mv_sort. Supported options: [\"asc\", \"desc\"]." - ] - }, - { - "query": "from a_index | eval mv_sort([\"a\", \"b\"], \"ASC\")", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval mv_sort([\"a\", \"b\"], \"DESC\")", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval result = case(false, 0, 1), round(result)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval result = case(false, 0, 1) | stats sum(result)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval result = case(false, 0, 1) | stats var0 = sum(result)", - "error": [], + "query": "from a_index | eval numberField == \"2022\"", + "error": [ + "Argument of [==] must be [number], found value [\"2022\"] type [string]" + ], "warning": [] }, { - "query": "from a_index | eval round(case(false, 0, 1))", - "error": [], + "query": "from a_index | eval dateField == stringField", + "error": [ + "Argument of [==] must be [string], found value [dateField] type [date]" + ], "warning": [] }, { - "query": "from a_index | eval 1 anno", + "query": "from a_index | eval stringField == dateField", "error": [ - "EVAL does not support [date_period] in expression [1 anno]" + "Argument of [==] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval var = 1 anno", + "query": "from a_index | eval stringField == 0", "error": [ - "Unexpected time interval qualifier: 'anno'" + "Argument of [==] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval now() + 1 anno", + "query": "from a_index | eval stringField == now()", "error": [ - "Unexpected time interval qualifier: 'anno'" + "Argument of [==] must be [string], found value [now()] type [date]" ], "warning": [] }, { - "query": "from a_index | eval 1 year", - "error": [ - "EVAL does not support [date_period] in expression [1 year]" - ], + "query": "from a_index | eval dateField == \"2022\"", + "error": [], "warning": [] }, { - "query": "from a_index | eval 1 year", - "error": [ - "EVAL does not support [date_period] in expression [1 year]" - ], + "query": "from a_index | eval \"2022\" == dateField", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 year", + "query": "from a_index | eval versionField == \"1.2.3\"", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 year", + "query": "from a_index | eval \"1.2.3\" == versionField", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 YEAR", + "query": "from a_index | eval booleanField == \"true\"", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Year", + "query": "from a_index | eval \"true\" == booleanField", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 year", + "query": "from a_index | eval ipField == \"136.36.3.205\"", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 year + 1 year", - "error": [ - "Argument of [+] must be [date], found value [1 year] type [duration]" - ], + "query": "from a_index | eval \"136.36.3.205\" == ipField", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 year", - "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 year] type [duration]" - ], + "query": "from a_index | eval numberField != 0", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 year", - "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 year] type [duration]" - ], + "query": "from a_index | eval NOT numberField != 0", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 year", - "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 year] type [duration]" - ], + "query": "from a_index | eval (numberField != 0)", + "error": [], "warning": [] }, { - "query": "from a_index | eval 1 years", - "error": [ - "EVAL does not support [date_period] in expression [1 years]" - ], + "query": "from a_index | eval (NOT (numberField != 0))", + "error": [], "warning": [] }, { - "query": "from a_index | eval 1 years", - "error": [ - "EVAL does not support [date_period] in expression [1 years]" - ], + "query": "from a_index | eval 1 != 0", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 years", + "query": "from a_index | eval stringField != stringField", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 years", + "query": "from a_index | eval numberField != numberField", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 YEARS", + "query": "from a_index | eval dateField != dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Years", + "query": "from a_index | eval booleanField != booleanField", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 years", + "query": "from a_index | eval ipField != ipField", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 years + 1 year", + "query": "from a_index | eval numberField != stringField", "error": [ - "Argument of [+] must be [date], found value [1 years] type [duration]" + "Argument of [!=] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 years", + "query": "from a_index | eval stringField != numberField", "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 years] type [duration]" + "Argument of [!=] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 years", + "query": "from a_index | eval numberField != \"2022\"", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 years] type [duration]" + "Argument of [!=] must be [number], found value [\"2022\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 years", + "query": "from a_index | eval dateField != stringField", "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 years] type [duration]" + "Argument of [!=] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval 1 month", + "query": "from a_index | eval stringField != dateField", "error": [ - "EVAL does not support [date_period] in expression [1 month]" + "Argument of [!=] must be [string], found value [dateField] type [date]" ], "warning": [] }, { - "query": "from a_index | eval 1 month", + "query": "from a_index | eval stringField != 0", "error": [ - "EVAL does not support [date_period] in expression [1 month]" + "Argument of [!=] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 month", - "error": [], + "query": "from a_index | eval stringField != now()", + "error": [ + "Argument of [!=] must be [string], found value [now()] type [date]" + ], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 month", + "query": "from a_index | eval dateField != \"2022\"", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 MONTH", + "query": "from a_index | eval \"2022\" != dateField", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Month", + "query": "from a_index | eval versionField != \"1.2.3\"", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 month", + "query": "from a_index | eval \"1.2.3\" != versionField", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 month + 1 year", - "error": [ - "Argument of [+] must be [date], found value [1 month] type [duration]" - ], + "query": "from a_index | eval booleanField != \"true\"", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 month", - "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 month] type [duration]" - ], + "query": "from a_index | eval \"true\" != booleanField", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 month", - "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 month] type [duration]" - ], + "query": "from a_index | eval ipField != \"136.36.3.205\"", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 month", - "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 month] type [duration]" - ], + "query": "from a_index | eval \"136.36.3.205\" != ipField", + "error": [], "warning": [] }, { - "query": "from a_index | eval 1 months", - "error": [ - "EVAL does not support [date_period] in expression [1 months]" - ], + "query": "from a_index | eval versionField in (\"1.2.3\", \"4.5.6\", to_version(\"2.3.2\"))", + "error": [], "warning": [] }, { - "query": "from a_index | eval 1 months", - "error": [ - "EVAL does not support [date_period] in expression [1 months]" - ], + "query": "from a_index | eval dateField in (\"2023-12-12\", \"2024-12-12\", date_parse(\"yyyy-MM-dd\", \"2025-12-12\"))", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 months", + "query": "from a_index | eval booleanField in (\"true\", \"false\", false)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 months", + "query": "from a_index | eval ipField in (\"136.36.3.205\", \"136.36.3.206\", to_ip(\"136.36.3.207\"))", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 MONTHS", + "query": "from a_index | eval numberField + 1", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Months", + "query": "from a_index | eval (numberField + 1)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 months", + "query": "from a_index | eval 1 + 1", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 months + 1 year", + "query": "from a_index | eval now() + now()", "error": [ - "Argument of [+] must be [date], found value [1 months] type [duration]" + "Argument of [+] must be [time_literal], found value [now()] type [date]" ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 months", + "query": "from a_index | eval 1 + \"1\"", "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 months] type [duration]" + "Argument of [+] must be [number], found value [\"1\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 months", + "query": "from a_index | eval \"1\" + 1", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 months] type [duration]" + "Argument of [+] must be [number], found value [\"1\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 months", + "query": "from a_index | eval numberField - 1", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval (numberField - 1)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval 1 - 1", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval now() - now()", "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 months] type [duration]" + "Argument of [-] must be [time_literal], found value [now()] type [date]" ], "warning": [] }, { - "query": "from a_index | eval 1 week", + "query": "from a_index | eval 1 - \"1\"", "error": [ - "EVAL does not support [date_period] in expression [1 week]" + "Argument of [-] must be [number], found value [\"1\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval 1 week", + "query": "from a_index | eval \"1\" - 1", "error": [ - "EVAL does not support [date_period] in expression [1 week]" + "Argument of [-] must be [number], found value [\"1\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 week", + "query": "from a_index | eval numberField * 1", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 week", + "query": "from a_index | eval (numberField * 1)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 WEEK", + "query": "from a_index | eval 1 * 1", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Week", + "query": "from a_index | eval now() * now()", + "error": [ + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [now()] type [date]" + ], + "warning": [] + }, + { + "query": "from a_index | eval 1 * \"1\"", + "error": [ + "Argument of [*] must be [number], found value [\"1\"] type [string]" + ], + "warning": [] + }, + { + "query": "from a_index | eval \"1\" * 1", + "error": [ + "Argument of [*] must be [number], found value [\"1\"] type [string]" + ], + "warning": [] + }, + { + "query": "from a_index | eval numberField / 1", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 week", + "query": "from a_index | eval (numberField / 1)", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 week + 1 year", + "query": "from a_index | eval 1 / 1", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval now() / now()", "error": [ - "Argument of [+] must be [date], found value [1 week] type [duration]" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [now()] type [date]" ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 week", + "query": "from a_index | eval 1 / \"1\"", "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 week] type [duration]" + "Argument of [/] must be [number], found value [\"1\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 week", + "query": "from a_index | eval \"1\" / 1", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 week] type [duration]" + "Argument of [/] must be [number], found value [\"1\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 week", + "query": "from a_index | eval numberField % 1", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval (numberField % 1)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval 1 % 1", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval now() % now()", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 week] type [duration]" + "Argument of [%] must be [number], found value [now()] type [date]" ], "warning": [] }, { - "query": "from a_index | eval 1 weeks", + "query": "from a_index | eval 1 % \"1\"", "error": [ - "EVAL does not support [date_period] in expression [1 weeks]" + "Argument of [%] must be [number], found value [\"1\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval 1 weeks", + "query": "from a_index | eval \"1\" % 1", "error": [ - "EVAL does not support [date_period] in expression [1 weeks]" + "Argument of [%] must be [number], found value [\"1\"] type [string]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 weeks", + "query": "from a_index | eval 1/0", "error": [], - "warning": [] + "warning": [ + "Cannot divide by zero: 1/0" + ] }, { - "query": "from a_index | eval var = dateField - 1 weeks", + "query": "from a_index | eval var = 1/0", "error": [], - "warning": [] + "warning": [ + "Cannot divide by zero: 1/0" + ] }, { - "query": "from a_index | eval var = dateField - 1 WEEKS", + "query": "from a_index | eval 1 + 1/0", "error": [], - "warning": [] + "warning": [ + "Cannot divide by zero: 1/0" + ] }, { - "query": "from a_index | eval var = dateField - 1 Weeks", + "query": "from a_index | eval 1%0", "error": [], - "warning": [] + "warning": [ + "Module by zero can return null value: 1%0" + ] }, { - "query": "from a_index | eval var = dateField + 1 weeks", + "query": "from a_index | eval var = 1%0", + "error": [], + "warning": [ + "Module by zero can return null value: 1%0" + ] + }, + { + "query": "from a_index | eval 1 + 1%0", + "error": [], + "warning": [ + "Module by zero can return null value: 1%0" + ] + }, + { + "query": "from a_index | eval stringField like \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 weeks + 1 year", - "error": [ - "Argument of [+] must be [date], found value [1 weeks] type [duration]" - ], + "query": "from a_index | eval stringField NOT like \"?a\"", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 weeks", - "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 weeks] type [duration]" - ], + "query": "from a_index | eval NOT stringField like \"?a\"", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 weeks", - "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 weeks] type [duration]" - ], + "query": "from a_index | eval NOT stringField NOT like \"?a\"", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 weeks", + "query": "from a_index | eval numberField like \"?a\"", "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 weeks] type [duration]" + "Argument of [like] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval 1 day", + "query": "from a_index | eval numberField NOT like \"?a\"", "error": [ - "EVAL does not support [date_period] in expression [1 day]" + "Argument of [not_like] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval 1 day", + "query": "from a_index | eval NOT numberField like \"?a\"", "error": [ - "EVAL does not support [date_period] in expression [1 day]" + "Argument of [like] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 day", - "error": [], + "query": "from a_index | eval NOT numberField NOT like \"?a\"", + "error": [ + "Argument of [not_like] must be [string], found value [numberField] type [number]" + ], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 day", + "query": "from a_index | eval stringField rlike \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 DAY", + "query": "from a_index | eval stringField NOT rlike \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Day", + "query": "from a_index | eval NOT stringField rlike \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 day", + "query": "from a_index | eval NOT stringField NOT rlike \"?a\"", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 day + 1 year", - "error": [ - "Argument of [+] must be [date], found value [1 day] type [duration]" - ], - "warning": [] - }, - { - "query": "from a_index | eval var = now() * 1 day", - "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 day] type [duration]" - ], - "warning": [] - }, - { - "query": "from a_index | eval var = now() / 1 day", + "query": "from a_index | eval numberField rlike \"?a\"", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 day] type [duration]" + "Argument of [rlike] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 day", + "query": "from a_index | eval numberField NOT rlike \"?a\"", "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 day] type [duration]" + "Argument of [not_rlike] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval 1 days", + "query": "from a_index | eval NOT numberField rlike \"?a\"", "error": [ - "EVAL does not support [date_period] in expression [1 days]" + "Argument of [rlike] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval 1 days", + "query": "from a_index | eval NOT numberField NOT rlike \"?a\"", "error": [ - "EVAL does not support [date_period] in expression [1 days]" + "Argument of [not_rlike] must be [string], found value [numberField] type [number]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 days", + "query": "from a_index | eval 1 in (1, 2, 3)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 days", + "query": "from a_index | eval numberField in (1, 2, 3)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 DAYS", + "query": "from a_index | eval numberField not in (1, 2, 3)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Days", + "query": "from a_index | eval numberField not in (1, 2, 3, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 days", + "query": "from a_index | eval 1 in (1, 2, 3, round(numberField))", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 days + 1 year", - "error": [ - "Argument of [+] must be [date], found value [1 days] type [duration]" - ], - "warning": [] - }, - { - "query": "from a_index | eval var = now() * 1 days", - "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 days] type [duration]" - ], + "query": "from a_index | eval \"a\" in (\"a\", \"b\", \"c\")", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 days", - "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 days] type [duration]" - ], + "query": "from a_index | eval stringField in (\"a\", \"b\", \"c\")", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 days", - "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 days] type [duration]" - ], + "query": "from a_index | eval stringField not in (\"a\", \"b\", \"c\")", + "error": [], "warning": [] }, { - "query": "from a_index | eval 1 hour", - "error": [ - "EVAL does not support [date_period] in expression [1 hour]" - ], + "query": "from a_index | eval stringField not in (\"a\", \"b\", \"c\", stringField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval 1 hour", - "error": [ - "EVAL does not support [date_period] in expression [1 hour]" - ], + "query": "from a_index | eval 1 in (\"a\", \"b\", \"c\")", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 hour", + "query": "from a_index | eval numberField in (\"a\", \"b\", \"c\")", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 hour", + "query": "from a_index | eval numberField not in (\"a\", \"b\", \"c\")", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 HOUR", + "query": "from a_index | eval numberField not in (1, 2, 3, stringField)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Hour", - "error": [], + "query": "from a_index | eval avg(numberField)", + "error": [ + "EVAL does not support function avg" + ], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 hour", + "query": "from a_index | stats avg(numberField) | eval `avg(numberField)` + 1", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 hour + 1 year", + "query": "from a_index | eval not", "error": [ - "Argument of [+] must be [date], found value [1 hour] type [duration]" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "Error: [not] function expects exactly one argument, got 0." ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 hour", + "query": "from a_index | eval in", "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 hour] type [duration]" + "SyntaxError: mismatched input 'in' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 hour", + "query": "from a_index | eval stringField in stringField", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 hour] type [duration]" + "SyntaxError: missing '(' at 'stringField'", + "SyntaxError: mismatched input '' expecting {',', ')'}" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 hour", + "query": "from a_index | eval stringField in stringField)", "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 hour] type [duration]" + "SyntaxError: missing '(' at 'stringField'", + "Error: [in] function expects exactly 2 arguments, got 1." ], "warning": [] }, { - "query": "from a_index | eval 1 hours", + "query": "from a_index | eval stringField not in stringField", "error": [ - "EVAL does not support [date_period] in expression [1 hours]" + "SyntaxError: missing '(' at 'stringField'", + "SyntaxError: mismatched input '' expecting {',', ')'}" ], "warning": [] }, { - "query": "from a_index | eval 1 hours", - "error": [ - "EVAL does not support [date_period] in expression [1 hours]" - ], - "warning": [] + "query": "from a_index | eval mv_sort([\"a\", \"b\"], \"bogus\")", + "error": [], + "warning": [ + "Invalid option [\"bogus\"] for mv_sort. Supported options: [\"asc\", \"desc\"]." + ] }, { - "query": "from a_index | eval var = now() - 1 hours", + "query": "from a_index | eval mv_sort([\"a\", \"b\"], \"ASC\")", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 hours", + "query": "from a_index | eval mv_sort([\"a\", \"b\"], \"DESC\")", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 HOURS", + "query": "from a_index | eval result = case(false, 0, 1), round(result)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Hours", + "query": "from a_index | eval result = case(false, 0, 1) | stats sum(result)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 hours", + "query": "from a_index | eval result = case(false, 0, 1) | stats var0 = sum(result)", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 hours + 1 year", - "error": [ - "Argument of [+] must be [date], found value [1 hours] type [duration]" - ], + "query": "from a_index | eval round(case(false, 0, 1))", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 hours", - "error": [ - "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 hours] type [duration]" + "query": "from a_index | eval 1 anno", + "error": [ + "EVAL does not support [date_period] in expression [1 anno]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 hours", + "query": "from a_index | eval var = 1 anno", "error": [ - "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 hours] type [duration]" + "Unexpected time interval qualifier: 'anno'" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 hours", + "query": "from a_index | eval now() + 1 anno", "error": [ - "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 hours] type [duration]" + "Unexpected time interval qualifier: 'anno'" ], "warning": [] }, { - "query": "from a_index | eval 1 minute", + "query": "from a_index | eval 1 year", "error": [ - "EVAL does not support [date_period] in expression [1 minute]" + "EVAL does not support [date_period] in expression [1 year]" ], "warning": [] }, { - "query": "from a_index | eval 1 minute", + "query": "from a_index | eval 1 year", "error": [ - "EVAL does not support [date_period] in expression [1 minute]" + "EVAL does not support [date_period] in expression [1 year]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 minute", + "query": "from a_index | eval var = now() - 1 year", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 minute", + "query": "from a_index | eval var = dateField - 1 year", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 MINUTE", + "query": "from a_index | eval var = dateField - 1 YEAR", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Minute", + "query": "from a_index | eval var = dateField - 1 Year", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 minute", + "query": "from a_index | eval var = dateField + 1 year", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 minute + 1 year", + "query": "from a_index | eval 1 year + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 minute] type [duration]" + "Argument of [+] must be [date], found value [1 year] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 minute", + "query": "from a_index | eval var = now() * 1 year", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 minute] type [duration]" + "Argument of [*] must be [number], found value [1 year] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 minute", + "query": "from a_index | eval var = now() / 1 year", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 minute] type [duration]" + "Argument of [/] must be [number], found value [1 year] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 minute", + "query": "from a_index | eval var = now() % 1 year", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 minute] type [duration]" + "Argument of [%] must be [number], found value [1 year] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval 1 minutes", + "query": "from a_index | eval 1 years", "error": [ - "EVAL does not support [date_period] in expression [1 minutes]" + "EVAL does not support [date_period] in expression [1 years]" ], "warning": [] }, { - "query": "from a_index | eval 1 minutes", + "query": "from a_index | eval 1 years", "error": [ - "EVAL does not support [date_period] in expression [1 minutes]" + "EVAL does not support [date_period] in expression [1 years]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 minutes", + "query": "from a_index | eval var = now() - 1 years", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 minutes", + "query": "from a_index | eval var = dateField - 1 years", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 MINUTES", + "query": "from a_index | eval var = dateField - 1 YEARS", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Minutes", + "query": "from a_index | eval var = dateField - 1 Years", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 minutes", + "query": "from a_index | eval var = dateField + 1 years", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 minutes + 1 year", + "query": "from a_index | eval 1 years + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 minutes] type [duration]" + "Argument of [+] must be [date], found value [1 years] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 minutes", + "query": "from a_index | eval var = now() * 1 years", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 minutes] type [duration]" + "Argument of [*] must be [number], found value [1 years] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 minutes", + "query": "from a_index | eval var = now() / 1 years", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 minutes] type [duration]" + "Argument of [/] must be [number], found value [1 years] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 minutes", + "query": "from a_index | eval var = now() % 1 years", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 minutes] type [duration]" + "Argument of [%] must be [number], found value [1 years] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval 1 second", + "query": "from a_index | eval 1 month", "error": [ - "EVAL does not support [date_period] in expression [1 second]" + "EVAL does not support [date_period] in expression [1 month]" ], "warning": [] }, { - "query": "from a_index | eval 1 second", + "query": "from a_index | eval 1 month", "error": [ - "EVAL does not support [date_period] in expression [1 second]" + "EVAL does not support [date_period] in expression [1 month]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 second", + "query": "from a_index | eval var = now() - 1 month", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 second", + "query": "from a_index | eval var = dateField - 1 month", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 SECOND", + "query": "from a_index | eval var = dateField - 1 MONTH", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Second", + "query": "from a_index | eval var = dateField - 1 Month", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 second", + "query": "from a_index | eval var = dateField + 1 month", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 second + 1 year", + "query": "from a_index | eval 1 month + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 second] type [duration]" + "Argument of [+] must be [date], found value [1 month] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 second", + "query": "from a_index | eval var = now() * 1 month", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 second] type [duration]" + "Argument of [*] must be [number], found value [1 month] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 second", + "query": "from a_index | eval var = now() / 1 month", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 second] type [duration]" + "Argument of [/] must be [number], found value [1 month] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 second", + "query": "from a_index | eval var = now() % 1 month", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 second] type [duration]" + "Argument of [%] must be [number], found value [1 month] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval 1 seconds", + "query": "from a_index | eval 1 months", "error": [ - "EVAL does not support [date_period] in expression [1 seconds]" + "EVAL does not support [date_period] in expression [1 months]" ], "warning": [] }, { - "query": "from a_index | eval 1 seconds", + "query": "from a_index | eval 1 months", "error": [ - "EVAL does not support [date_period] in expression [1 seconds]" + "EVAL does not support [date_period] in expression [1 months]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 seconds", + "query": "from a_index | eval var = now() - 1 months", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 seconds", + "query": "from a_index | eval var = dateField - 1 months", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 SECONDS", + "query": "from a_index | eval var = dateField - 1 MONTHS", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Seconds", + "query": "from a_index | eval var = dateField - 1 Months", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 seconds", + "query": "from a_index | eval var = dateField + 1 months", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 seconds + 1 year", + "query": "from a_index | eval 1 months + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 seconds] type [duration]" + "Argument of [+] must be [date], found value [1 months] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 seconds", + "query": "from a_index | eval var = now() * 1 months", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 seconds] type [duration]" + "Argument of [*] must be [number], found value [1 months] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 seconds", + "query": "from a_index | eval var = now() / 1 months", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 seconds] type [duration]" + "Argument of [/] must be [number], found value [1 months] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 seconds", + "query": "from a_index | eval var = now() % 1 months", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 seconds] type [duration]" + "Argument of [%] must be [number], found value [1 months] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval 1 millisecond", + "query": "from a_index | eval 1 week", "error": [ - "EVAL does not support [date_period] in expression [1 millisecond]" + "EVAL does not support [date_period] in expression [1 week]" ], "warning": [] }, { - "query": "from a_index | eval 1 millisecond", + "query": "from a_index | eval 1 week", "error": [ - "EVAL does not support [date_period] in expression [1 millisecond]" + "EVAL does not support [date_period] in expression [1 week]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 millisecond", + "query": "from a_index | eval var = now() - 1 week", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 millisecond", + "query": "from a_index | eval var = dateField - 1 week", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 MILLISECOND", + "query": "from a_index | eval var = dateField - 1 WEEK", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Millisecond", + "query": "from a_index | eval var = dateField - 1 Week", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 millisecond", + "query": "from a_index | eval var = dateField + 1 week", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 millisecond + 1 year", + "query": "from a_index | eval 1 week + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 millisecond] type [duration]" + "Argument of [+] must be [date], found value [1 week] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 millisecond", + "query": "from a_index | eval var = now() * 1 week", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 millisecond] type [duration]" + "Argument of [*] must be [number], found value [1 week] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 millisecond", + "query": "from a_index | eval var = now() / 1 week", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 millisecond] type [duration]" + "Argument of [/] must be [number], found value [1 week] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 millisecond", + "query": "from a_index | eval var = now() % 1 week", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 millisecond] type [duration]" + "Argument of [%] must be [number], found value [1 week] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval 1 milliseconds", + "query": "from a_index | eval 1 weeks", "error": [ - "EVAL does not support [date_period] in expression [1 milliseconds]" + "EVAL does not support [date_period] in expression [1 weeks]" ], "warning": [] }, { - "query": "from a_index | eval 1 milliseconds", + "query": "from a_index | eval 1 weeks", "error": [ - "EVAL does not support [date_period] in expression [1 milliseconds]" + "EVAL does not support [date_period] in expression [1 weeks]" ], "warning": [] }, { - "query": "from a_index | eval var = now() - 1 milliseconds", + "query": "from a_index | eval var = now() - 1 weeks", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 milliseconds", + "query": "from a_index | eval var = dateField - 1 weeks", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 MILLISECONDS", + "query": "from a_index | eval var = dateField - 1 WEEKS", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField - 1 Milliseconds", + "query": "from a_index | eval var = dateField - 1 Weeks", "error": [], "warning": [] }, { - "query": "from a_index | eval var = dateField + 1 milliseconds", + "query": "from a_index | eval var = dateField + 1 weeks", "error": [], "warning": [] }, { - "query": "from a_index | eval 1 milliseconds + 1 year", + "query": "from a_index | eval 1 weeks + 1 year", "error": [ - "Argument of [+] must be [date], found value [1 milliseconds] type [duration]" + "Argument of [+] must be [date], found value [1 weeks] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() * 1 milliseconds", + "query": "from a_index | eval var = now() * 1 weeks", "error": [ "Argument of [*] must be [number], found value [now()] type [date]", - "Argument of [*] must be [number], found value [1 milliseconds] type [duration]" + "Argument of [*] must be [number], found value [1 weeks] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() / 1 milliseconds", + "query": "from a_index | eval var = now() / 1 weeks", "error": [ "Argument of [/] must be [number], found value [now()] type [date]", - "Argument of [/] must be [number], found value [1 milliseconds] type [duration]" + "Argument of [/] must be [number], found value [1 weeks] type [duration]" ], "warning": [] }, { - "query": "from a_index | eval var = now() % 1 milliseconds", + "query": "from a_index | eval var = now() % 1 weeks", "error": [ "Argument of [%] must be [number], found value [now()] type [date]", - "Argument of [%] must be [number], found value [1 milliseconds] type [duration]" + "Argument of [%] must be [number], found value [1 weeks] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats ", + "query": "from a_index | eval 1 day", + "error": [ + "EVAL does not support [date_period] in expression [1 day]" + ], + "warning": [] + }, + { + "query": "from a_index | eval 1 day", "error": [ - "At least one aggregation or grouping expression required in [STATS]" + "EVAL does not support [date_period] in expression [1 day]" ], "warning": [] }, { - "query": "from a_index | stats by stringField", + "query": "from a_index | eval var = now() - 1 day", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval var = dateField - 1 day", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval var = dateField - 1 DAY", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval var = dateField - 1 Day", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval var = dateField + 1 day", "error": [], "warning": [] }, { - "query": "from a_index | stats by ", + "query": "from a_index | eval 1 day + 1 year", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "Argument of [+] must be [date], found value [1 day] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats numberField ", + "query": "from a_index | eval var = now() * 1 day", "error": [ - "Expected an aggregate function or group but got [numberField] of type [FieldAttribute]" + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 day] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats numberField=", + "query": "from a_index | eval var = now() / 1 day", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 day] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats numberField=5 by ", + "query": "from a_index | eval var = now() % 1 day", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 day] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats avg(numberField) by wrongField", + "query": "from a_index | eval 1 days", "error": [ - "Unknown column [wrongField]" + "EVAL does not support [date_period] in expression [1 days]" ], "warning": [] }, { - "query": "from a_index | stats avg(numberField) by wrongField + 1", + "query": "from a_index | eval 1 days", "error": [ - "Unknown column [wrongField]" + "EVAL does not support [date_period] in expression [1 days]" ], "warning": [] }, { - "query": "from a_index | stats avg(numberField) by var0 = wrongField + 1", - "error": [ - "Unknown column [wrongField]" - ], + "query": "from a_index | eval var = now() - 1 days", + "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField) by 1", + "query": "from a_index | eval var = dateField - 1 days", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField) by percentile(numberField)", - "error": [ - "STATS BY does not support function percentile" - ], + "query": "from a_index | eval var = dateField - 1 DAYS", + "error": [], "warning": [] }, { - "query": "from a_index | stats count(`numberField`)", + "query": "from a_index | eval var = dateField - 1 Days", "error": [], "warning": [] }, { - "query": "from a_index | stats count(stringField == \"a\" or null)", + "query": "from a_index | eval var = dateField + 1 days", "error": [], "warning": [] }, { - "query": "from a_index | stats count(`numberField`) | keep `count(``numberField``)` ", - "error": [], + "query": "from a_index | eval 1 days + 1 year", + "error": [ + "Argument of [+] must be [date], found value [1 days] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats count(`numberField`) | drop `count(``numberField``)` ", - "error": [], + "query": "from a_index | eval var = now() * 1 days", + "error": [ + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 days] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats count(`numberField`) | eval `count(``numberField``)` ", - "error": [], + "query": "from a_index | eval var = now() / 1 days", + "error": [ + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 days] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats avg(numberField) by stringField, percentile(numberField) by ipField", + "query": "from a_index | eval var = now() % 1 days", "error": [ - "SyntaxError: mismatched input 'by' expecting ", - "STATS BY does not support function percentile" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 days] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats avg(numberField), percentile(numberField, 50) by ipField", - "error": [], + "query": "from a_index | eval 1 hour", + "error": [ + "EVAL does not support [date_period] in expression [1 hour]" + ], "warning": [] }, { - "query": "from a_index | stats avg(numberField), percentile(numberField, 50) BY ipField", - "error": [], + "query": "from a_index | eval 1 hour", + "error": [ + "EVAL does not support [date_period] in expression [1 hour]" + ], "warning": [] }, { - "query": "from a_index | stats avg(numberField) + percentile(numberField, 50) BY ipField", + "query": "from a_index | eval var = now() - 1 hour", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField) - percentile(numberField, 50) BY ipField", + "query": "from a_index | eval var = dateField - 1 hour", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField) * percentile(numberField, 50) BY ipField", + "query": "from a_index | eval var = dateField - 1 HOUR", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField) / percentile(numberField, 50) BY ipField", + "query": "from a_index | eval var = dateField - 1 Hour", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField) % percentile(numberField, 50) BY ipField", + "query": "from a_index | eval var = dateField + 1 hour", "error": [], "warning": [] }, { - "query": "from a_index | stats count(* + 1) BY ipField", + "query": "from a_index | eval 1 hour + 1 year", "error": [ - "SyntaxError: no viable alternative at input 'count(* +'" + "Argument of [+] must be [date], found value [1 hour] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats count(* + round(numberField)) BY ipField", + "query": "from a_index | eval var = now() * 1 hour", "error": [ - "SyntaxError: no viable alternative at input 'count(* +'" + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 hour] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats count(round(*)) BY ipField", + "query": "from a_index | eval var = now() / 1 hour", "error": [ - "Using wildcards (*) in round is not allowed" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 hour] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats count(count(*)) BY ipField", + "query": "from a_index | eval var = now() % 1 hour", "error": [ - "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [count(*)] of type [number]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 hour] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats numberField + 1", + "query": "from a_index | eval 1 hours", "error": [ - "At least one aggregation function required in [STATS], found [numberField+1]" + "EVAL does not support [date_period] in expression [1 hours]" ], "warning": [] }, { - "query": "from a_index | stats 5 + avg(numberField) +1", - "error": [], + "query": "from a_index | eval 1 hours", + "error": [ + "EVAL does not support [date_period] in expression [1 hours]" + ], "warning": [] }, { - "query": "from a_index | stats 5 +1 + avg(numberField)", + "query": "from a_index | eval var = now() - 1 hours", "error": [], "warning": [] }, { - "query": "from a_index | stats 5 +1 + numberField", - "error": [ - "At least one aggregation function required in [STATS], found [5+1+numberField]" - ], + "query": "from a_index | eval var = dateField - 1 hours", + "error": [], "warning": [] }, { - "query": "from a_index | stats 5 + numberField +1", - "error": [ - "At least one aggregation function required in [STATS], found [5+numberField+1]" - ], + "query": "from a_index | eval var = dateField - 1 HOURS", + "error": [], "warning": [] }, { - "query": "from a_index | stats 5 + numberField +1, var0 = sum(numberField)", - "error": [ - "At least one aggregation function required in [STATS], found [5+numberField+1]" - ], + "query": "from a_index | eval var = dateField - 1 Hours", + "error": [], "warning": [] }, { - "query": "from a_index | stats round( sum(numberField) )", + "query": "from a_index | eval var = dateField + 1 hours", "error": [], "warning": [] }, { - "query": "from a_index | stats round( sum(numberField) ) + round( sum(numberField) )", - "error": [], + "query": "from a_index | eval 1 hours + 1 year", + "error": [ + "Argument of [+] must be [date], found value [1 hours] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats round( numberField + sum(numberField) )", + "query": "from a_index | eval var = now() * 1 hours", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(numberField+sum(numberField))]" + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 hours] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats round( numberField + sum(numberField) ), var0 = sum(numberField)", + "query": "from a_index | eval var = now() / 1 hours", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(numberField+sum(numberField))]" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 hours] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats var0 = round( numberField + sum(numberField) ), var1 = sum(numberField)", + "query": "from a_index | eval var = now() % 1 hours", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(numberField+sum(numberField))]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 hours] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats round( sum(numberField + numberField) )", - "error": [], + "query": "from a_index | eval 1 minute", + "error": [ + "EVAL does not support [date_period] in expression [1 minute]" + ], "warning": [] }, { - "query": "from a_index | stats round( sum(numberField + round(numberField)) )", - "error": [], + "query": "from a_index | eval 1 minute", + "error": [ + "EVAL does not support [date_period] in expression [1 minute]" + ], "warning": [] }, { - "query": "from a_index | stats round( sum(numberField + round(numberField)) ) + round( sum(numberField + round(numberField)) )", + "query": "from a_index | eval var = now() - 1 minute", "error": [], "warning": [] }, { - "query": "from a_index | stats sum(round( numberField ) )", + "query": "from a_index | eval var = dateField - 1 minute", "error": [], "warning": [] }, { - "query": "from a_index | stats sum(round( numberField ) ) + sum(round( numberField ) )", + "query": "from a_index | eval var = dateField - 1 MINUTE", "error": [], "warning": [] }, { - "query": "from a_index | stats 5 + avg(numberField) +1+1", + "query": "from a_index | eval var = dateField - 1 Minute", "error": [], "warning": [] }, { - "query": "from a_index | stats 5 +1+1 + avg(numberField)", + "query": "from a_index | eval var = dateField + 1 minute", "error": [], "warning": [] }, { - "query": "from a_index | stats 5 +1+1 + numberField", + "query": "from a_index | eval 1 minute + 1 year", "error": [ - "At least one aggregation function required in [STATS], found [5+1+1+numberField]" + "Argument of [+] must be [date], found value [1 minute] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats 5 + numberField +1+1", + "query": "from a_index | eval var = now() * 1 minute", "error": [ - "At least one aggregation function required in [STATS], found [5+numberField+1+1]" + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 minute] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats 5 + numberField +1+1, var0 = sum(numberField)", + "query": "from a_index | eval var = now() / 1 minute", "error": [ - "At least one aggregation function required in [STATS], found [5+numberField+1+1]" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 minute] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats round(round( sum(numberField) ))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats round(round( sum(numberField) )) + round(round( sum(numberField) ))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats round(round( numberField + sum(numberField) ))", + "query": "from a_index | eval var = now() % 1 minute", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(round(numberField+sum(numberField)))]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 minute] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats round(round( numberField + sum(numberField) )), var0 = sum(numberField)", + "query": "from a_index | eval 1 minutes", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(round(numberField+sum(numberField)))]" + "EVAL does not support [date_period] in expression [1 minutes]" ], "warning": [] }, { - "query": "from a_index | stats var0 = round(round( numberField + sum(numberField) )), var1 = sum(numberField)", + "query": "from a_index | eval 1 minutes", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(round(numberField+sum(numberField)))]" + "EVAL does not support [date_period] in expression [1 minutes]" ], "warning": [] }, { - "query": "from a_index | stats round(round( sum(numberField + numberField) ))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats round(round( sum(numberField + round(numberField)) ))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats round(round( sum(numberField + round(numberField)) )) + round(round( sum(numberField + round(numberField)) ))", + "query": "from a_index | eval var = now() - 1 minutes", "error": [], "warning": [] }, { - "query": "from a_index | stats sum(round(round( numberField )) )", + "query": "from a_index | eval var = dateField - 1 minutes", "error": [], "warning": [] }, { - "query": "from a_index | stats sum(round(round( numberField )) ) + sum(round(round( numberField )) )", + "query": "from a_index | eval var = dateField - 1 MINUTES", "error": [], "warning": [] }, { - "query": "from a_index | stats 5 + avg(numberField) +1+1+1", + "query": "from a_index | eval var = dateField - 1 Minutes", "error": [], "warning": [] }, { - "query": "from a_index | stats 5 +1+1+1 + avg(numberField)", + "query": "from a_index | eval var = dateField + 1 minutes", "error": [], "warning": [] }, { - "query": "from a_index | stats 5 +1+1+1 + numberField", + "query": "from a_index | eval 1 minutes + 1 year", "error": [ - "At least one aggregation function required in [STATS], found [5+1+1+1+numberField]" + "Argument of [+] must be [date], found value [1 minutes] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats 5 + numberField +1+1+1", + "query": "from a_index | eval var = now() * 1 minutes", "error": [ - "At least one aggregation function required in [STATS], found [5+numberField+1+1+1]" + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 minutes] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats 5 + numberField +1+1+1, var0 = sum(numberField)", + "query": "from a_index | eval var = now() / 1 minutes", "error": [ - "At least one aggregation function required in [STATS], found [5+numberField+1+1+1]" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 minutes] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats round(round(round( sum(numberField) )))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats round(round(round( sum(numberField) ))) + round(round(round( sum(numberField) )))", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats round(round(round( numberField + sum(numberField) )))", + "query": "from a_index | eval var = now() % 1 minutes", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(round(round(numberField+sum(numberField))))]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 minutes] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats round(round(round( numberField + sum(numberField) ))), var0 = sum(numberField)", + "query": "from a_index | eval 1 second", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(round(round(numberField+sum(numberField))))]" + "EVAL does not support [date_period] in expression [1 second]" ], "warning": [] }, { - "query": "from a_index | stats var0 = round(round(round( numberField + sum(numberField) ))), var1 = sum(numberField)", + "query": "from a_index | eval 1 second", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(round(round(numberField+sum(numberField))))]" + "EVAL does not support [date_period] in expression [1 second]" ], "warning": [] }, { - "query": "from a_index | stats round(round(round( sum(numberField + numberField) )))", + "query": "from a_index | eval var = now() - 1 second", "error": [], "warning": [] }, { - "query": "from a_index | stats round(round(round( sum(numberField + round(numberField)) )))", + "query": "from a_index | eval var = dateField - 1 second", "error": [], "warning": [] }, { - "query": "from a_index | stats round(round(round( sum(numberField + round(numberField)) ))) + round(round(round( sum(numberField + round(numberField)) )))", + "query": "from a_index | eval var = dateField - 1 SECOND", "error": [], "warning": [] }, { - "query": "from a_index | stats sum(round(round(round( numberField ))) )", + "query": "from a_index | eval var = dateField - 1 Second", "error": [], "warning": [] }, { - "query": "from a_index | stats sum(round(round(round( numberField ))) ) + sum(round(round(round( numberField ))) )", + "query": "from a_index | eval var = dateField + 1 second", "error": [], "warning": [] }, { - "query": "from a_index | stats 5 + avg(numberField) +1+1+1+1", - "error": [], + "query": "from a_index | eval 1 second + 1 year", + "error": [ + "Argument of [+] must be [date], found value [1 second] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats 5 +1+1+1+1 + avg(numberField)", - "error": [], + "query": "from a_index | eval var = now() * 1 second", + "error": [ + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 second] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats 5 +1+1+1+1 + numberField", + "query": "from a_index | eval var = now() / 1 second", "error": [ - "At least one aggregation function required in [STATS], found [5+1+1+1+1+numberField]" + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 second] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats 5 + numberField +1+1+1+1", + "query": "from a_index | eval var = now() % 1 second", "error": [ - "At least one aggregation function required in [STATS], found [5+numberField+1+1+1+1]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 second] type [duration]" ], "warning": [] }, { - "query": "from a_index | stats 5 + numberField +1+1+1+1, var0 = sum(numberField)", + "query": "from a_index | eval 1 seconds", "error": [ - "At least one aggregation function required in [STATS], found [5+numberField+1+1+1+1]" + "EVAL does not support [date_period] in expression [1 seconds]" ], "warning": [] }, { - "query": "from a_index | stats round(round(round(round( sum(numberField) ))))", - "error": [], + "query": "from a_index | eval 1 seconds", + "error": [ + "EVAL does not support [date_period] in expression [1 seconds]" + ], "warning": [] }, { - "query": "from a_index | stats round(round(round(round( sum(numberField) )))) + round(round(round(round( sum(numberField) ))))", + "query": "from a_index | eval var = now() - 1 seconds", "error": [], "warning": [] }, { - "query": "from a_index | stats round(round(round(round( numberField + sum(numberField) ))))", - "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(round(round(round(numberField+sum(numberField)))))]" - ], + "query": "from a_index | eval var = dateField - 1 seconds", + "error": [], "warning": [] }, { - "query": "from a_index | stats round(round(round(round( numberField + sum(numberField) )))), var0 = sum(numberField)", - "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(round(round(round(numberField+sum(numberField)))))]" - ], + "query": "from a_index | eval var = dateField - 1 SECONDS", + "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = round(round(round(round( numberField + sum(numberField) )))), var1 = sum(numberField)", - "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [round(round(round(round(numberField+sum(numberField)))))]" - ], + "query": "from a_index | eval var = dateField - 1 Seconds", + "error": [], "warning": [] }, { - "query": "from a_index | stats round(round(round(round( sum(numberField + numberField) ))))", + "query": "from a_index | eval var = dateField + 1 seconds", "error": [], "warning": [] }, { - "query": "from a_index | stats round(round(round(round( sum(numberField + round(numberField)) ))))", - "error": [], + "query": "from a_index | eval 1 seconds + 1 year", + "error": [ + "Argument of [+] must be [date], found value [1 seconds] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats round(round(round(round( sum(numberField + round(numberField)) )))) + round(round(round(round( sum(numberField + round(numberField)) ))))", - "error": [], + "query": "from a_index | eval var = now() * 1 seconds", + "error": [ + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 seconds] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats sum(round(round(round(round( numberField )))) )", - "error": [], + "query": "from a_index | eval var = now() / 1 seconds", + "error": [ + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 seconds] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats sum(round(round(round(round( numberField )))) ) + sum(round(round(round(round( numberField )))) )", - "error": [], + "query": "from a_index | eval var = now() % 1 seconds", + "error": [ + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 seconds] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats 5 + numberField + 1", + "query": "from a_index | eval 1 millisecond", "error": [ - "At least one aggregation function required in [STATS], found [5+numberField+1]" + "EVAL does not support [date_period] in expression [1 millisecond]" ], "warning": [] }, { - "query": "from a_index | stats numberField + 1 by ipField", + "query": "from a_index | eval 1 millisecond", "error": [ - "At least one aggregation function required in [STATS], found [numberField+1]" + "EVAL does not support [date_period] in expression [1 millisecond]" ], "warning": [] }, { - "query": "from a_index | stats avg(numberField), percentile(numberField, 50) + 1 by ipField", + "query": "from a_index | eval var = now() - 1 millisecond", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval var = dateField - 1 millisecond", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval var = dateField - 1 MILLISECOND", "error": [], "warning": [] }, { - "query": "from a_index | stats count(*)", + "query": "from a_index | eval var = dateField - 1 Millisecond", "error": [], "warning": [] }, { - "query": "from a_index | stats count()", + "query": "from a_index | eval var = dateField + 1 millisecond", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = count(*)", - "error": [], + "query": "from a_index | eval 1 millisecond + 1 year", + "error": [ + "Argument of [+] must be [date], found value [1 millisecond] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats var0 = count()", - "error": [], + "query": "from a_index | eval var = now() * 1 millisecond", + "error": [ + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 millisecond] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats var0 = avg(numberField), count(*)", - "error": [], + "query": "from a_index | eval var = now() / 1 millisecond", + "error": [ + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 millisecond] type [duration]" + ], "warning": [] }, { - "query": "from a_index | stats var0 = avg(fn(number)), count(*)", + "query": "from a_index | eval var = now() % 1 millisecond", "error": [ - "Unknown function [fn]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 millisecond] type [duration]" ], "warning": [] }, { - "query": "from a_index | STATS sum( numberField ) + abs( numberField ) ", + "query": "from a_index | eval 1 milliseconds", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [sum(numberField)+abs(numberField)]" + "EVAL does not support [date_period] in expression [1 milliseconds]" ], "warning": [] }, { - "query": "from a_index | STATS abs( numberField + sum( numberField )) ", + "query": "from a_index | eval 1 milliseconds", "error": [ - "Cannot combine aggregation and non-aggregation values in [STATS], found [abs(numberField+sum(numberField))]" + "EVAL does not support [date_period] in expression [1 milliseconds]" ], "warning": [] }, { - "query": "FROM index\n | EVAL numberField * 3.281\n | STATS avg_numberField = AVG(`numberField * 3.281`)", + "query": "from a_index | eval var = now() - 1 milliseconds", "error": [], "warning": [] }, { - "query": "FROM index | STATS AVG(numberField) by round(numberField) + 1 | EVAL `round(numberField) + 1` / 2", + "query": "from a_index | eval var = dateField - 1 milliseconds", "error": [], "warning": [] }, { - "query": "from a_index | stats sum(case(false, 0, 1))", + "query": "from a_index | eval var = dateField - 1 MILLISECONDS", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = sum( case(false, 0, 1))", + "query": "from a_index | eval var = dateField - 1 Milliseconds", "error": [], "warning": [] }, { - "query": "from index | stats by bucket(dateField, abs(numberField), \"\", \"\")", - "error": [ - "Argument of [bucket] must be a constant, received [abs(numberField)]" - ], + "query": "from a_index | eval var = dateField + 1 milliseconds", + "error": [], "warning": [] }, { - "query": "from index | stats by bucket(dateField, abs(length(numberField)), \"\", \"\")", + "query": "from a_index | eval 1 milliseconds + 1 year", "error": [ - "Argument of [bucket] must be a constant, received [abs(length(numberField))]" + "Argument of [+] must be [date], found value [1 milliseconds] type [duration]" ], "warning": [] }, { - "query": "from index | stats by bucket(dateField, pi(), \"\", \"\")", - "error": [], - "warning": [] - }, - { - "query": "from index | stats by bucket(dateField, 1 + 30 / 10, \"\", \"\")", - "error": [], + "query": "from a_index | eval var = now() * 1 milliseconds", + "error": [ + "Argument of [*] must be [number], found value [now()] type [date]", + "Argument of [*] must be [number], found value [1 milliseconds] type [duration]" + ], "warning": [] }, { - "query": "from index | stats by bucket(dateField, 1 + 30 / 10, concat(\"\", \"\"), \"\")", - "error": [], + "query": "from a_index | eval var = now() / 1 milliseconds", + "error": [ + "Argument of [/] must be [number], found value [now()] type [date]", + "Argument of [/] must be [number], found value [1 milliseconds] type [duration]" + ], "warning": [] }, { - "query": "from index | stats by bucket(dateField, numberField, stringField, stringField)", + "query": "from a_index | eval var = now() % 1 milliseconds", "error": [ - "Argument of [bucket] must be a constant, received [numberField]", - "Argument of [bucket] must be a constant, received [stringField]", - "Argument of [bucket] must be a constant, received [stringField]" + "Argument of [%] must be [number], found value [now()] type [date]", + "Argument of [%] must be [number], found value [1 milliseconds] type [duration]" ], "warning": [] }, @@ -8948,13 +7988,6 @@ "error": [], "warning": [] }, - { - "query": "from a_index | eval 1::foo", - "error": [ - "Invalid type [foo] for casting" - ], - "warning": [] - }, { "query": "from a_index | eval 1::string::long::double", "error": [], @@ -23328,2574 +22361,2942 @@ "warning": [] }, { - "query": "from a_index | stats median(numberField / 2)", + "query": "from a_index | stats median(numberField / 2)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats var0 = median(numberField / 2)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), median(numberField / 2)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), var0 = median(numberField / 2)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats var0 = median(numberField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), median(numberField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), var0 = median(numberField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats median(numberField) by round(numberField / 2)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats var0 = median(numberField) by var1 = round(numberField / 2)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), median(numberField) by round(numberField / 2), ipField", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), var0 = median(numberField) by var1 = round(numberField / 2), ipField", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), median(numberField) by round(numberField / 2), numberField / 2", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), var0 = median(numberField) by var1 = round(numberField / 2), numberField / 2", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats var = median(avg(numberField))", + "error": [ + "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" + ], + "warning": [] + }, + { + "query": "from a_index | stats median(avg(numberField))", + "error": [ + "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" + ], + "warning": [] + }, + { + "query": "from a_index | stats median(stringField)", + "error": [ + "Argument of [median] must be [number], found value [stringField] type [string]" + ], + "warning": [] + }, + { + "query": "from a_index | stats var = median(*)", + "error": [ + "Using wildcards (*) in median is not allowed" + ], + "warning": [] + }, + { + "query": "from a_index | sort median(numberField)", + "error": [ + "SORT does not support function median" + ], + "warning": [] + }, + { + "query": "from a_index | where median(numberField)", + "error": [ + "WHERE does not support function median" + ], + "warning": [] + }, + { + "query": "from a_index | where median(numberField) > 0", + "error": [ + "WHERE does not support function median" + ], + "warning": [] + }, + { + "query": "from a_index | eval var = median(numberField)", + "error": [ + "EVAL does not support function median" + ], + "warning": [] + }, + { + "query": "from a_index | eval var = median(numberField) > 0", + "error": [ + "EVAL does not support function median" + ], + "warning": [] + }, + { + "query": "from a_index | eval median(numberField)", + "error": [ + "EVAL does not support function median" + ], + "warning": [] + }, + { + "query": "from a_index | eval median(numberField) > 0", + "error": [ + "EVAL does not support function median" + ], + "warning": [] + }, + { + "query": "from a_index | stats median(booleanField)", + "error": [ + "Argument of [median] must be [number], found value [booleanField] type [boolean]" + ], + "warning": [] + }, + { + "query": "from a_index | stats median(null)", + "error": [], + "warning": [] + }, + { + "query": "row nullVar = null | stats median(nullVar)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats var = median_absolute_deviation(numberField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats median_absolute_deviation(numberField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats var = round(median_absolute_deviation(numberField))", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats round(median_absolute_deviation(numberField))", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats var = round(median_absolute_deviation(numberField)) + median_absolute_deviation(numberField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats round(median_absolute_deviation(numberField)) + median_absolute_deviation(numberField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats median_absolute_deviation(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = median(numberField / 2)", + "query": "from a_index | stats var0 = median_absolute_deviation(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), median(numberField / 2)", + "query": "from a_index | stats avg(numberField), median_absolute_deviation(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = median(numberField / 2)", + "query": "from a_index | stats avg(numberField), var0 = median_absolute_deviation(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = median(numberField)", + "query": "from a_index | stats var0 = median_absolute_deviation(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), median(numberField)", + "query": "from a_index | stats avg(numberField), median_absolute_deviation(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = median(numberField)", + "query": "from a_index | stats avg(numberField), var0 = median_absolute_deviation(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats median(numberField) by round(numberField / 2)", + "query": "from a_index | stats median_absolute_deviation(numberField) by round(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = median(numberField) by var1 = round(numberField / 2)", + "query": "from a_index | stats var0 = median_absolute_deviation(numberField) by var1 = round(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), median(numberField) by round(numberField / 2), ipField", + "query": "from a_index | stats avg(numberField), median_absolute_deviation(numberField) by round(numberField / 2), ipField", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = median(numberField) by var1 = round(numberField / 2), ipField", + "query": "from a_index | stats avg(numberField), var0 = median_absolute_deviation(numberField) by var1 = round(numberField / 2), ipField", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), median(numberField) by round(numberField / 2), numberField / 2", + "query": "from a_index | stats avg(numberField), median_absolute_deviation(numberField) by round(numberField / 2), numberField / 2", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = median(numberField) by var1 = round(numberField / 2), numberField / 2", + "query": "from a_index | stats avg(numberField), var0 = median_absolute_deviation(numberField) by var1 = round(numberField / 2), numberField / 2", "error": [], "warning": [] }, { - "query": "from a_index | stats var = median(avg(numberField))", + "query": "from a_index | stats var = median_absolute_deviation(avg(numberField))", "error": [ "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" ], "warning": [] }, { - "query": "from a_index | stats median(avg(numberField))", + "query": "from a_index | stats median_absolute_deviation(avg(numberField))", "error": [ "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" ], "warning": [] }, { - "query": "from a_index | stats median(stringField)", + "query": "from a_index | stats median_absolute_deviation(stringField)", "error": [ - "Argument of [median] must be [number], found value [stringField] type [string]" + "Argument of [median_absolute_deviation] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | stats var = median(*)", + "query": "from a_index | stats var = median_absolute_deviation(*)", "error": [ - "Using wildcards (*) in median is not allowed" + "Using wildcards (*) in median_absolute_deviation is not allowed" ], "warning": [] }, { - "query": "from a_index | sort median(numberField)", + "query": "from a_index | sort median_absolute_deviation(numberField)", "error": [ - "SORT does not support function median" + "SORT does not support function median_absolute_deviation" ], "warning": [] }, { - "query": "from a_index | where median(numberField)", + "query": "from a_index | where median_absolute_deviation(numberField)", "error": [ - "WHERE does not support function median" + "WHERE does not support function median_absolute_deviation" ], "warning": [] }, { - "query": "from a_index | where median(numberField) > 0", + "query": "from a_index | where median_absolute_deviation(numberField) > 0", "error": [ - "WHERE does not support function median" + "WHERE does not support function median_absolute_deviation" ], "warning": [] }, { - "query": "from a_index | eval var = median(numberField)", + "query": "from a_index | eval var = median_absolute_deviation(numberField)", "error": [ - "EVAL does not support function median" + "EVAL does not support function median_absolute_deviation" ], "warning": [] }, { - "query": "from a_index | eval var = median(numberField) > 0", + "query": "from a_index | eval var = median_absolute_deviation(numberField) > 0", "error": [ - "EVAL does not support function median" + "EVAL does not support function median_absolute_deviation" ], "warning": [] }, { - "query": "from a_index | eval median(numberField)", + "query": "from a_index | eval median_absolute_deviation(numberField)", "error": [ - "EVAL does not support function median" + "EVAL does not support function median_absolute_deviation" ], "warning": [] }, { - "query": "from a_index | eval median(numberField) > 0", + "query": "from a_index | eval median_absolute_deviation(numberField) > 0", "error": [ - "EVAL does not support function median" + "EVAL does not support function median_absolute_deviation" ], "warning": [] }, { - "query": "from a_index | stats median(booleanField)", + "query": "from a_index | stats median_absolute_deviation(booleanField)", "error": [ - "Argument of [median] must be [number], found value [booleanField] type [boolean]" + "Argument of [median_absolute_deviation] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | stats median(null)", + "query": "from a_index | stats median_absolute_deviation(null)", "error": [], "warning": [] }, { - "query": "row nullVar = null | stats median(nullVar)", + "query": "row nullVar = null | stats median_absolute_deviation(nullVar)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = median_absolute_deviation(numberField)", + "query": "from a_index | stats var = percentile(numberField, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats median_absolute_deviation(numberField)", + "query": "from a_index | stats percentile(numberField, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(median_absolute_deviation(numberField))", + "query": "from a_index | stats var = round(percentile(numberField, 5))", "error": [], "warning": [] }, { - "query": "from a_index | stats round(median_absolute_deviation(numberField))", + "query": "from a_index | stats round(percentile(numberField, 5))", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(median_absolute_deviation(numberField)) + median_absolute_deviation(numberField)", + "query": "from a_index | stats var = round(percentile(numberField, 5)) + percentile(numberField, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats round(median_absolute_deviation(numberField)) + median_absolute_deviation(numberField)", + "query": "from a_index | stats round(percentile(numberField, 5)) + percentile(numberField, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats median_absolute_deviation(numberField / 2)", + "query": "from a_index | stats percentile(numberField, numberField)", + "error": [ + "Argument of [percentile] must be a constant, received [numberField]" + ], + "warning": [] + }, + { + "query": "from a_index | stats percentile(numberField / 2, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = median_absolute_deviation(numberField / 2)", + "query": "from a_index | stats var0 = percentile(numberField / 2, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), median_absolute_deviation(numberField / 2)", + "query": "from a_index | stats avg(numberField), percentile(numberField / 2, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = median_absolute_deviation(numberField / 2)", + "query": "from a_index | stats avg(numberField), var0 = percentile(numberField / 2, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = median_absolute_deviation(numberField)", + "query": "from a_index | stats var0 = percentile(numberField, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), median_absolute_deviation(numberField)", + "query": "from a_index | stats avg(numberField), percentile(numberField, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = median_absolute_deviation(numberField)", + "query": "from a_index | stats avg(numberField), var0 = percentile(numberField, 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats median_absolute_deviation(numberField) by round(numberField / 2)", + "query": "from a_index | stats percentile(numberField, 5) by round(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = median_absolute_deviation(numberField) by var1 = round(numberField / 2)", + "query": "from a_index | stats var0 = percentile(numberField, 5) by var1 = round(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), median_absolute_deviation(numberField) by round(numberField / 2), ipField", + "query": "from a_index | stats avg(numberField), percentile(numberField, 5) by round(numberField / 2), ipField", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = median_absolute_deviation(numberField) by var1 = round(numberField / 2), ipField", + "query": "from a_index | stats avg(numberField), var0 = percentile(numberField, 5) by var1 = round(numberField / 2), ipField", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), median_absolute_deviation(numberField) by round(numberField / 2), numberField / 2", + "query": "from a_index | stats avg(numberField), percentile(numberField, 5) by round(numberField / 2), numberField / 2", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = median_absolute_deviation(numberField) by var1 = round(numberField / 2), numberField / 2", + "query": "from a_index | stats avg(numberField), var0 = percentile(numberField, 5) by var1 = round(numberField / 2), numberField / 2", "error": [], "warning": [] }, { - "query": "from a_index | stats var = median_absolute_deviation(avg(numberField))", + "query": "from a_index | stats var = percentile(avg(numberField), 5)", "error": [ "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" ], "warning": [] }, { - "query": "from a_index | stats median_absolute_deviation(avg(numberField))", + "query": "from a_index | stats percentile(avg(numberField), 5)", "error": [ "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" ], "warning": [] }, { - "query": "from a_index | stats median_absolute_deviation(stringField)", + "query": "from a_index | stats percentile(stringField, 5)", "error": [ - "Argument of [median_absolute_deviation] must be [number], found value [stringField] type [string]" + "Argument of [percentile] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | stats var = median_absolute_deviation(*)", + "query": "from a_index | sort percentile(numberField, 5)", "error": [ - "Using wildcards (*) in median_absolute_deviation is not allowed" + "SORT does not support function percentile" ], "warning": [] }, { - "query": "from a_index | sort median_absolute_deviation(numberField)", + "query": "from a_index | where percentile(numberField, 5)", "error": [ - "SORT does not support function median_absolute_deviation" + "WHERE does not support function percentile" ], "warning": [] }, { - "query": "from a_index | where median_absolute_deviation(numberField)", + "query": "from a_index | where percentile(numberField, 5) > 0", "error": [ - "WHERE does not support function median_absolute_deviation" + "WHERE does not support function percentile" ], "warning": [] }, { - "query": "from a_index | where median_absolute_deviation(numberField) > 0", + "query": "from a_index | eval var = percentile(numberField, 5)", "error": [ - "WHERE does not support function median_absolute_deviation" + "EVAL does not support function percentile" ], "warning": [] }, { - "query": "from a_index | eval var = median_absolute_deviation(numberField)", + "query": "from a_index | eval var = percentile(numberField, 5) > 0", "error": [ - "EVAL does not support function median_absolute_deviation" + "EVAL does not support function percentile" ], "warning": [] }, { - "query": "from a_index | eval var = median_absolute_deviation(numberField) > 0", + "query": "from a_index | eval percentile(numberField, 5)", "error": [ - "EVAL does not support function median_absolute_deviation" + "EVAL does not support function percentile" ], "warning": [] }, { - "query": "from a_index | eval median_absolute_deviation(numberField)", + "query": "from a_index | eval percentile(numberField, 5) > 0", "error": [ - "EVAL does not support function median_absolute_deviation" + "EVAL does not support function percentile" ], "warning": [] }, { - "query": "from a_index | eval median_absolute_deviation(numberField) > 0", + "query": "from a_index | stats percentile(booleanField, 5)", "error": [ - "EVAL does not support function median_absolute_deviation" + "Argument of [percentile] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | stats median_absolute_deviation(booleanField)", + "query": "from a_index | stats percentile(null, null)", + "error": [], + "warning": [] + }, + { + "query": "row nullVar = null | stats percentile(nullVar, nullVar)", "error": [ - "Argument of [median_absolute_deviation] must be [number], found value [booleanField] type [boolean]" + "Argument of [percentile] must be a constant, received [nullVar]" ], "warning": [] }, { - "query": "from a_index | stats median_absolute_deviation(null)", + "query": "from a_index | stats var = max(numberField)", "error": [], "warning": [] }, { - "query": "row nullVar = null | stats median_absolute_deviation(nullVar)", + "query": "from a_index | stats max(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = percentile(numberField, 5)", + "query": "from a_index | stats var = round(max(numberField))", "error": [], "warning": [] }, { - "query": "from a_index | stats percentile(numberField, 5)", + "query": "from a_index | stats round(max(numberField))", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(percentile(numberField, 5))", + "query": "from a_index | stats var = round(max(numberField)) + max(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats round(percentile(numberField, 5))", + "query": "from a_index | stats round(max(numberField)) + max(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(percentile(numberField, 5)) + percentile(numberField, 5)", + "query": "from a_index | stats max(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats round(percentile(numberField, 5)) + percentile(numberField, 5)", + "query": "from a_index | stats var0 = max(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats percentile(numberField, numberField)", - "error": [ - "Argument of [percentile] must be a constant, received [numberField]" - ], + "query": "from a_index | stats avg(numberField), max(numberField / 2)", + "error": [], "warning": [] }, { - "query": "from a_index | stats percentile(numberField / 2, 5)", + "query": "from a_index | stats avg(numberField), var0 = max(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = percentile(numberField / 2, 5)", + "query": "from a_index | stats var0 = max(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), percentile(numberField / 2, 5)", + "query": "from a_index | stats avg(numberField), max(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = percentile(numberField / 2, 5)", + "query": "from a_index | stats avg(numberField), var0 = max(numberField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats max(numberField) by round(numberField / 2)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats var0 = max(numberField) by var1 = round(numberField / 2)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), max(numberField) by round(numberField / 2), ipField", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), var0 = max(numberField) by var1 = round(numberField / 2), ipField", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), max(numberField) by round(numberField / 2), numberField / 2", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats avg(numberField), var0 = max(numberField) by var1 = round(numberField / 2), numberField / 2", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = percentile(numberField, 5)", + "query": "from a_index | stats var = max(avg(numberField))", + "error": [ + "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" + ], + "warning": [] + }, + { + "query": "from a_index | stats max(avg(numberField))", + "error": [ + "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" + ], + "warning": [] + }, + { + "query": "from a_index | stats max(stringField)", + "error": [ + "Argument of [max] must be [number], found value [stringField] type [string]" + ], + "warning": [] + }, + { + "query": "from a_index | stats var = max(*)", + "error": [ + "Using wildcards (*) in max is not allowed" + ], + "warning": [] + }, + { + "query": "from a_index | stats var = max(dateField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), percentile(numberField, 5)", + "query": "from a_index | stats max(dateField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = percentile(numberField, 5)", + "query": "from a_index | stats var = round(max(dateField))", "error": [], "warning": [] }, { - "query": "from a_index | stats percentile(numberField, 5) by round(numberField / 2)", + "query": "from a_index | stats round(max(dateField))", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = percentile(numberField, 5) by var1 = round(numberField / 2)", + "query": "from a_index | stats var = round(max(dateField)) + max(dateField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), percentile(numberField, 5) by round(numberField / 2), ipField", + "query": "from a_index | stats round(max(dateField)) + max(dateField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = percentile(numberField, 5) by var1 = round(numberField / 2), ipField", - "error": [], + "query": "from a_index | sort max(numberField)", + "error": [ + "SORT does not support function max" + ], "warning": [] }, { - "query": "from a_index | stats avg(numberField), percentile(numberField, 5) by round(numberField / 2), numberField / 2", - "error": [], + "query": "from a_index | where max(numberField)", + "error": [ + "WHERE does not support function max" + ], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = percentile(numberField, 5) by var1 = round(numberField / 2), numberField / 2", - "error": [], + "query": "from a_index | where max(numberField) > 0", + "error": [ + "WHERE does not support function max" + ], "warning": [] }, { - "query": "from a_index | stats var = percentile(avg(numberField), 5)", + "query": "from a_index | where max(dateField)", "error": [ - "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" + "WHERE does not support function max" ], "warning": [] }, { - "query": "from a_index | stats percentile(avg(numberField), 5)", + "query": "from a_index | where max(dateField) > 0", "error": [ - "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" + "WHERE does not support function max" ], "warning": [] }, { - "query": "from a_index | stats percentile(stringField, 5)", + "query": "from a_index | eval var = max(numberField)", "error": [ - "Argument of [percentile] must be [number], found value [stringField] type [string]" + "EVAL does not support function max" ], "warning": [] }, { - "query": "from a_index | sort percentile(numberField, 5)", + "query": "from a_index | eval var = max(numberField) > 0", "error": [ - "SORT does not support function percentile" + "EVAL does not support function max" ], "warning": [] }, { - "query": "from a_index | where percentile(numberField, 5)", + "query": "from a_index | eval max(numberField)", "error": [ - "WHERE does not support function percentile" + "EVAL does not support function max" ], "warning": [] }, { - "query": "from a_index | where percentile(numberField, 5) > 0", + "query": "from a_index | eval max(numberField) > 0", "error": [ - "WHERE does not support function percentile" + "EVAL does not support function max" ], "warning": [] }, { - "query": "from a_index | eval var = percentile(numberField, 5)", + "query": "from a_index | eval var = max(dateField)", "error": [ - "EVAL does not support function percentile" + "EVAL does not support function max" ], "warning": [] }, { - "query": "from a_index | eval var = percentile(numberField, 5) > 0", + "query": "from a_index | eval var = max(dateField) > 0", "error": [ - "EVAL does not support function percentile" + "EVAL does not support function max" ], "warning": [] }, { - "query": "from a_index | eval percentile(numberField, 5)", + "query": "from a_index | eval max(dateField)", "error": [ - "EVAL does not support function percentile" + "EVAL does not support function max" ], "warning": [] }, { - "query": "from a_index | eval percentile(numberField, 5) > 0", + "query": "from a_index | eval max(dateField) > 0", "error": [ - "EVAL does not support function percentile" + "EVAL does not support function max" ], "warning": [] }, { - "query": "from a_index | stats percentile(booleanField, 5)", + "query": "from a_index | stats max(booleanField)", "error": [ - "Argument of [percentile] must be [number], found value [booleanField] type [boolean]" + "Argument of [max] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | stats percentile(null, null)", + "query": "from a_index | stats max(null)", "error": [], "warning": [] }, { - "query": "row nullVar = null | stats percentile(nullVar, nullVar)", + "query": "row nullVar = null | stats max(nullVar)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats max(\"2022\")", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats max(concat(\"20\", \"22\"))", "error": [ - "Argument of [percentile] must be a constant, received [nullVar]" + "Argument of [max] must be [number], found value [concat(\"20\", \"22\")] type [string]" ], "warning": [] }, { - "query": "from a_index | stats var = max(numberField)", + "query": "from a_index | stats var = min(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats max(numberField)", + "query": "from a_index | stats min(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(max(numberField))", + "query": "from a_index | stats var = round(min(numberField))", "error": [], "warning": [] }, { - "query": "from a_index | stats round(max(numberField))", + "query": "from a_index | stats round(min(numberField))", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(max(numberField)) + max(numberField)", + "query": "from a_index | stats var = round(min(numberField)) + min(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats round(max(numberField)) + max(numberField)", + "query": "from a_index | stats round(min(numberField)) + min(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats max(numberField / 2)", + "query": "from a_index | stats min(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = max(numberField / 2)", + "query": "from a_index | stats var0 = min(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), max(numberField / 2)", + "query": "from a_index | stats avg(numberField), min(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = max(numberField / 2)", + "query": "from a_index | stats avg(numberField), var0 = min(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = max(numberField)", + "query": "from a_index | stats var0 = min(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), max(numberField)", + "query": "from a_index | stats avg(numberField), min(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = max(numberField)", + "query": "from a_index | stats avg(numberField), var0 = min(numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats max(numberField) by round(numberField / 2)", + "query": "from a_index | stats min(numberField) by round(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = max(numberField) by var1 = round(numberField / 2)", + "query": "from a_index | stats var0 = min(numberField) by var1 = round(numberField / 2)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), max(numberField) by round(numberField / 2), ipField", + "query": "from a_index | stats avg(numberField), min(numberField) by round(numberField / 2), ipField", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = max(numberField) by var1 = round(numberField / 2), ipField", + "query": "from a_index | stats avg(numberField), var0 = min(numberField) by var1 = round(numberField / 2), ipField", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), max(numberField) by round(numberField / 2), numberField / 2", + "query": "from a_index | stats avg(numberField), min(numberField) by round(numberField / 2), numberField / 2", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = max(numberField) by var1 = round(numberField / 2), numberField / 2", + "query": "from a_index | stats avg(numberField), var0 = min(numberField) by var1 = round(numberField / 2), numberField / 2", "error": [], "warning": [] }, { - "query": "from a_index | stats var = max(avg(numberField))", + "query": "from a_index | stats var = min(avg(numberField))", "error": [ "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" ], "warning": [] }, { - "query": "from a_index | stats max(avg(numberField))", + "query": "from a_index | stats min(avg(numberField))", "error": [ "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" ], "warning": [] }, { - "query": "from a_index | stats max(stringField)", + "query": "from a_index | stats min(stringField)", "error": [ - "Argument of [max] must be [number], found value [stringField] type [string]" + "Argument of [min] must be [number], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | stats var = max(*)", + "query": "from a_index | stats var = min(*)", "error": [ - "Using wildcards (*) in max is not allowed" + "Using wildcards (*) in min is not allowed" ], "warning": [] }, { - "query": "from a_index | stats var = max(dateField)", + "query": "from a_index | stats var = min(dateField)", "error": [], "warning": [] }, { - "query": "from a_index | stats max(dateField)", + "query": "from a_index | stats min(dateField)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(max(dateField))", + "query": "from a_index | stats var = round(min(dateField))", "error": [], "warning": [] }, { - "query": "from a_index | stats round(max(dateField))", + "query": "from a_index | stats round(min(dateField))", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(max(dateField)) + max(dateField)", + "query": "from a_index | stats var = round(min(dateField)) + min(dateField)", "error": [], "warning": [] }, { - "query": "from a_index | stats round(max(dateField)) + max(dateField)", + "query": "from a_index | stats round(min(dateField)) + min(dateField)", "error": [], "warning": [] }, { - "query": "from a_index | sort max(numberField)", + "query": "from a_index | sort min(numberField)", "error": [ - "SORT does not support function max" + "SORT does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | where min(numberField)", + "error": [ + "WHERE does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | where min(numberField) > 0", + "error": [ + "WHERE does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | where min(dateField)", + "error": [ + "WHERE does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | where min(dateField) > 0", + "error": [ + "WHERE does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | eval var = min(numberField)", + "error": [ + "EVAL does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | eval var = min(numberField) > 0", + "error": [ + "EVAL does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | eval min(numberField)", + "error": [ + "EVAL does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | eval min(numberField) > 0", + "error": [ + "EVAL does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | eval var = min(dateField)", + "error": [ + "EVAL does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | eval var = min(dateField) > 0", + "error": [ + "EVAL does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | eval min(dateField)", + "error": [ + "EVAL does not support function min" + ], + "warning": [] + }, + { + "query": "from a_index | eval min(dateField) > 0", + "error": [ + "EVAL does not support function min" ], "warning": [] }, { - "query": "from a_index | where max(numberField)", - "error": [ - "WHERE does not support function max" - ], + "query": "from a_index | stats min(booleanField)", + "error": [ + "Argument of [min] must be [number], found value [booleanField] type [boolean]" + ], + "warning": [] + }, + { + "query": "from a_index | stats min(null)", + "error": [], + "warning": [] + }, + { + "query": "row nullVar = null | stats min(nullVar)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats min(\"2022\")", + "error": [], "warning": [] }, { - "query": "from a_index | where max(numberField) > 0", + "query": "from a_index | stats min(concat(\"20\", \"22\"))", "error": [ - "WHERE does not support function max" + "Argument of [min] must be [number], found value [concat(\"20\", \"22\")] type [string]" ], "warning": [] }, { - "query": "from a_index | where max(dateField)", - "error": [ - "WHERE does not support function max" - ], + "query": "from a_index | stats var = count(stringField)", + "error": [], "warning": [] }, { - "query": "from a_index | where max(dateField) > 0", - "error": [ - "WHERE does not support function max" - ], + "query": "from a_index | stats count(stringField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = max(numberField)", - "error": [ - "EVAL does not support function max" - ], + "query": "from a_index | stats var = round(count(stringField))", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = max(numberField) > 0", - "error": [ - "EVAL does not support function max" - ], + "query": "from a_index | stats round(count(stringField))", + "error": [], "warning": [] }, { - "query": "from a_index | eval max(numberField)", - "error": [ - "EVAL does not support function max" - ], + "query": "from a_index | stats var = round(count(stringField)) + count(stringField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval max(numberField) > 0", - "error": [ - "EVAL does not support function max" - ], + "query": "from a_index | stats round(count(stringField)) + count(stringField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = max(dateField)", + "query": "from a_index | sort count(stringField)", "error": [ - "EVAL does not support function max" + "SORT does not support function count" ], "warning": [] }, { - "query": "from a_index | eval var = max(dateField) > 0", + "query": "from a_index | where count(stringField)", "error": [ - "EVAL does not support function max" + "WHERE does not support function count" ], "warning": [] }, { - "query": "from a_index | eval max(dateField)", + "query": "from a_index | where count(stringField) > 0", "error": [ - "EVAL does not support function max" + "WHERE does not support function count" ], "warning": [] }, { - "query": "from a_index | eval max(dateField) > 0", + "query": "from a_index | eval var = count(stringField)", "error": [ - "EVAL does not support function max" + "EVAL does not support function count" ], "warning": [] }, { - "query": "from a_index | stats max(booleanField)", + "query": "from a_index | eval var = count(stringField) > 0", "error": [ - "Argument of [max] must be [number], found value [booleanField] type [boolean]" + "EVAL does not support function count" ], "warning": [] }, { - "query": "from a_index | stats max(null)", - "error": [], - "warning": [] - }, - { - "query": "row nullVar = null | stats max(nullVar)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats max(\"2022\")", - "error": [], + "query": "from a_index | eval count(stringField)", + "error": [ + "EVAL does not support function count" + ], "warning": [] }, { - "query": "from a_index | stats max(concat(\"20\", \"22\"))", + "query": "from a_index | eval count(stringField) > 0", "error": [ - "Argument of [max] must be [number], found value [concat(\"20\", \"22\")] type [string]" + "EVAL does not support function count" ], "warning": [] }, { - "query": "from a_index | stats var = min(numberField)", + "query": "from a_index | stats count(null)", "error": [], "warning": [] }, { - "query": "from a_index | stats min(numberField)", + "query": "row nullVar = null | stats count(nullVar)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(min(numberField))", + "query": "from a_index | stats var = count_distinct(stringField, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats round(min(numberField))", + "query": "from a_index | stats count_distinct(stringField, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(min(numberField)) + min(numberField)", + "query": "from a_index | stats var = round(count_distinct(stringField, numberField))", "error": [], "warning": [] }, { - "query": "from a_index | stats round(min(numberField)) + min(numberField)", + "query": "from a_index | stats round(count_distinct(stringField, numberField))", "error": [], "warning": [] }, { - "query": "from a_index | stats min(numberField / 2)", + "query": "from a_index | stats var = round(count_distinct(stringField, numberField)) + count_distinct(stringField, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats var0 = min(numberField / 2)", + "query": "from a_index | stats round(count_distinct(stringField, numberField)) + count_distinct(stringField, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), min(numberField / 2)", - "error": [], + "query": "from a_index | sort count_distinct(stringField, numberField)", + "error": [ + "SORT does not support function count_distinct" + ], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = min(numberField / 2)", - "error": [], + "query": "from a_index | where count_distinct(stringField, numberField)", + "error": [ + "WHERE does not support function count_distinct" + ], "warning": [] }, { - "query": "from a_index | stats var0 = min(numberField)", - "error": [], + "query": "from a_index | where count_distinct(stringField, numberField) > 0", + "error": [ + "WHERE does not support function count_distinct" + ], "warning": [] }, { - "query": "from a_index | stats avg(numberField), min(numberField)", - "error": [], + "query": "from a_index | eval var = count_distinct(stringField, numberField)", + "error": [ + "EVAL does not support function count_distinct" + ], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = min(numberField)", - "error": [], + "query": "from a_index | eval var = count_distinct(stringField, numberField) > 0", + "error": [ + "EVAL does not support function count_distinct" + ], "warning": [] }, { - "query": "from a_index | stats min(numberField) by round(numberField / 2)", - "error": [], + "query": "from a_index | eval count_distinct(stringField, numberField)", + "error": [ + "EVAL does not support function count_distinct" + ], "warning": [] }, { - "query": "from a_index | stats var0 = min(numberField) by var1 = round(numberField / 2)", - "error": [], + "query": "from a_index | eval count_distinct(stringField, numberField) > 0", + "error": [ + "EVAL does not support function count_distinct" + ], "warning": [] }, { - "query": "from a_index | stats avg(numberField), min(numberField) by round(numberField / 2), ipField", + "query": "from a_index | stats count_distinct(null, null)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = min(numberField) by var1 = round(numberField / 2), ipField", + "query": "row nullVar = null | stats count_distinct(nullVar, nullVar)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), min(numberField) by round(numberField / 2), numberField / 2", + "query": "from a_index | stats var = st_centroid_agg(cartesianPointField)", "error": [], "warning": [] }, { - "query": "from a_index | stats avg(numberField), var0 = min(numberField) by var1 = round(numberField / 2), numberField / 2", + "query": "from a_index | stats st_centroid_agg(cartesianPointField)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = min(avg(numberField))", + "query": "from a_index | stats var = st_centroid_agg(avg(numberField))", "error": [ "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" ], "warning": [] }, { - "query": "from a_index | stats min(avg(numberField))", + "query": "from a_index | stats st_centroid_agg(avg(numberField))", "error": [ "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" ], "warning": [] }, { - "query": "from a_index | stats min(stringField)", + "query": "from a_index | stats st_centroid_agg(stringField)", "error": [ - "Argument of [min] must be [number], found value [stringField] type [string]" + "Argument of [st_centroid_agg] must be [cartesian_point], found value [stringField] type [string]" ], "warning": [] }, { - "query": "from a_index | stats var = min(*)", + "query": "from a_index | stats var = st_centroid_agg(*)", "error": [ - "Using wildcards (*) in min is not allowed" + "Using wildcards (*) in st_centroid_agg is not allowed" ], "warning": [] }, { - "query": "from a_index | stats var = min(dateField)", + "query": "from a_index | stats var = st_centroid_agg(geoPointField)", "error": [], "warning": [] }, { - "query": "from a_index | stats min(dateField)", + "query": "from a_index | stats st_centroid_agg(geoPointField)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(min(dateField))", - "error": [], + "query": "from a_index | sort st_centroid_agg(cartesianPointField)", + "error": [ + "SORT does not support function st_centroid_agg" + ], "warning": [] }, { - "query": "from a_index | stats round(min(dateField))", - "error": [], + "query": "from a_index | where st_centroid_agg(cartesianPointField)", + "error": [ + "WHERE does not support function st_centroid_agg" + ], "warning": [] }, { - "query": "from a_index | stats var = round(min(dateField)) + min(dateField)", - "error": [], + "query": "from a_index | where st_centroid_agg(cartesianPointField) > 0", + "error": [ + "WHERE does not support function st_centroid_agg" + ], "warning": [] }, { - "query": "from a_index | stats round(min(dateField)) + min(dateField)", - "error": [], + "query": "from a_index | where st_centroid_agg(geoPointField)", + "error": [ + "WHERE does not support function st_centroid_agg" + ], "warning": [] }, { - "query": "from a_index | sort min(numberField)", + "query": "from a_index | where st_centroid_agg(geoPointField) > 0", "error": [ - "SORT does not support function min" + "WHERE does not support function st_centroid_agg" ], "warning": [] }, { - "query": "from a_index | where min(numberField)", + "query": "from a_index | eval var = st_centroid_agg(cartesianPointField)", "error": [ - "WHERE does not support function min" + "EVAL does not support function st_centroid_agg" ], "warning": [] }, { - "query": "from a_index | where min(numberField) > 0", + "query": "from a_index | eval var = st_centroid_agg(cartesianPointField) > 0", "error": [ - "WHERE does not support function min" + "EVAL does not support function st_centroid_agg" ], "warning": [] }, { - "query": "from a_index | where min(dateField)", + "query": "from a_index | eval st_centroid_agg(cartesianPointField)", "error": [ - "WHERE does not support function min" + "EVAL does not support function st_centroid_agg" ], "warning": [] }, { - "query": "from a_index | where min(dateField) > 0", + "query": "from a_index | eval st_centroid_agg(cartesianPointField) > 0", "error": [ - "WHERE does not support function min" + "EVAL does not support function st_centroid_agg" ], "warning": [] }, { - "query": "from a_index | eval var = min(numberField)", + "query": "from a_index | eval var = st_centroid_agg(geoPointField)", "error": [ - "EVAL does not support function min" + "EVAL does not support function st_centroid_agg" ], "warning": [] }, { - "query": "from a_index | eval var = min(numberField) > 0", + "query": "from a_index | eval var = st_centroid_agg(geoPointField) > 0", "error": [ - "EVAL does not support function min" + "EVAL does not support function st_centroid_agg" ], "warning": [] }, { - "query": "from a_index | eval min(numberField)", + "query": "from a_index | eval st_centroid_agg(geoPointField)", "error": [ - "EVAL does not support function min" + "EVAL does not support function st_centroid_agg" ], "warning": [] }, { - "query": "from a_index | eval min(numberField) > 0", + "query": "from a_index | eval st_centroid_agg(geoPointField) > 0", "error": [ - "EVAL does not support function min" + "EVAL does not support function st_centroid_agg" + ], + "warning": [] + }, + { + "query": "from a_index | stats st_centroid_agg(booleanField)", + "error": [ + "Argument of [st_centroid_agg] must be [cartesian_point], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval var = min(dateField)", + "query": "from a_index | stats st_centroid_agg(null)", + "error": [], + "warning": [] + }, + { + "query": "row nullVar = null | stats st_centroid_agg(nullVar)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats var = values(stringField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | stats values(stringField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | sort values(stringField)", "error": [ - "EVAL does not support function min" + "SORT does not support function values" ], "warning": [] }, { - "query": "from a_index | eval var = min(dateField) > 0", + "query": "from a_index | where values(stringField)", "error": [ - "EVAL does not support function min" + "WHERE does not support function values" ], "warning": [] }, { - "query": "from a_index | eval min(dateField)", + "query": "from a_index | where values(stringField) > 0", "error": [ - "EVAL does not support function min" + "WHERE does not support function values" ], "warning": [] }, { - "query": "from a_index | eval min(dateField) > 0", + "query": "from a_index | eval var = values(stringField)", "error": [ - "EVAL does not support function min" + "EVAL does not support function values" ], "warning": [] }, { - "query": "from a_index | stats min(booleanField)", + "query": "from a_index | eval var = values(stringField) > 0", "error": [ - "Argument of [min] must be [number], found value [booleanField] type [boolean]" + "EVAL does not support function values" ], "warning": [] }, { - "query": "from a_index | stats min(null)", - "error": [], - "warning": [] - }, - { - "query": "row nullVar = null | stats min(nullVar)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats min(\"2022\")", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats min(concat(\"20\", \"22\"))", + "query": "from a_index | eval values(stringField)", "error": [ - "Argument of [min] must be [number], found value [concat(\"20\", \"22\")] type [string]" + "EVAL does not support function values" ], "warning": [] }, { - "query": "from a_index | stats var = count(stringField)", - "error": [], + "query": "from a_index | eval values(stringField) > 0", + "error": [ + "EVAL does not support function values" + ], "warning": [] }, { - "query": "from a_index | stats count(stringField)", + "query": "from a_index | stats values(null)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(count(stringField))", + "query": "row nullVar = null | stats values(nullVar)", "error": [], "warning": [] }, { - "query": "from a_index | stats round(count(stringField))", + "query": "from a_index | stats by bucket(dateField, 1 year)", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(count(stringField)) + count(stringField)", + "query": "from a_index | stats by bin(dateField, 1 year)", "error": [], "warning": [] }, { - "query": "from a_index | stats round(count(stringField)) + count(stringField)", + "query": "from a_index | stats by bucket(numberField, 5)", "error": [], "warning": [] }, { - "query": "from a_index | sort count(stringField)", + "query": "from a_index | stats by bucket(numberField, numberField)", "error": [ - "SORT does not support function count" + "Argument of [bucket] must be a constant, received [numberField]" ], "warning": [] }, { - "query": "from a_index | where count(stringField)", - "error": [ - "WHERE does not support function count" - ], + "query": "from a_index | stats by bin(numberField, 5)", + "error": [], "warning": [] }, { - "query": "from a_index | where count(stringField) > 0", - "error": [ - "WHERE does not support function count" - ], + "query": "from a_index | stats by bucket(dateField, 5, \"a\", \"a\")", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = count(stringField)", + "query": "from a_index | stats by bucket(dateField, numberField, stringField, stringField)", "error": [ - "EVAL does not support function count" + "Argument of [bucket] must be a constant, received [numberField]", + "Argument of [bucket] must be a constant, received [stringField]", + "Argument of [bucket] must be a constant, received [stringField]" ], "warning": [] }, { - "query": "from a_index | eval var = count(stringField) > 0", - "error": [ - "EVAL does not support function count" - ], + "query": "from a_index | stats by bin(dateField, 5, \"a\", \"a\")", + "error": [], "warning": [] }, { - "query": "from a_index | eval count(stringField)", - "error": [ - "EVAL does not support function count" - ], + "query": "from a_index | stats by bucket(dateField, 5, now(), now())", + "error": [], "warning": [] }, { - "query": "from a_index | eval count(stringField) > 0", + "query": "from a_index | stats by bucket(dateField, numberField, dateField, dateField)", "error": [ - "EVAL does not support function count" + "Argument of [bucket] must be a constant, received [numberField]", + "Argument of [bucket] must be a constant, received [dateField]", + "Argument of [bucket] must be a constant, received [dateField]" ], "warning": [] }, { - "query": "from a_index | stats count(null)", + "query": "from a_index | stats by bin(dateField, 5, now(), now())", "error": [], "warning": [] }, { - "query": "row nullVar = null | stats count(nullVar)", + "query": "from a_index | stats by bucket(dateField, 5, \"a\", now())", "error": [], "warning": [] }, { - "query": "from a_index | stats var = count_distinct(stringField, numberField)", - "error": [], + "query": "from a_index | stats by bucket(dateField, numberField, stringField, dateField)", + "error": [ + "Argument of [bucket] must be a constant, received [numberField]", + "Argument of [bucket] must be a constant, received [stringField]", + "Argument of [bucket] must be a constant, received [dateField]" + ], "warning": [] }, { - "query": "from a_index | stats count_distinct(stringField, numberField)", + "query": "from a_index | stats by bin(dateField, 5, \"a\", now())", "error": [], "warning": [] }, { - "query": "from a_index | stats var = round(count_distinct(stringField, numberField))", + "query": "from a_index | stats by bucket(dateField, 5, now(), \"a\")", "error": [], "warning": [] }, { - "query": "from a_index | stats round(count_distinct(stringField, numberField))", - "error": [], + "query": "from a_index | stats by bucket(dateField, numberField, dateField, stringField)", + "error": [ + "Argument of [bucket] must be a constant, received [numberField]", + "Argument of [bucket] must be a constant, received [dateField]", + "Argument of [bucket] must be a constant, received [stringField]" + ], "warning": [] }, { - "query": "from a_index | stats var = round(count_distinct(stringField, numberField)) + count_distinct(stringField, numberField)", + "query": "from a_index | stats by bin(dateField, 5, now(), \"a\")", "error": [], "warning": [] }, { - "query": "from a_index | stats round(count_distinct(stringField, numberField)) + count_distinct(stringField, numberField)", + "query": "from a_index | stats by bucket(numberField, 5, 5, 5)", "error": [], "warning": [] }, { - "query": "from a_index | sort count_distinct(stringField, numberField)", + "query": "from a_index | stats by bucket(numberField, numberField, numberField, numberField)", "error": [ - "SORT does not support function count_distinct" + "Argument of [bucket] must be a constant, received [numberField]", + "Argument of [bucket] must be a constant, received [numberField]", + "Argument of [bucket] must be a constant, received [numberField]" ], "warning": [] }, { - "query": "from a_index | where count_distinct(stringField, numberField)", - "error": [ - "WHERE does not support function count_distinct" - ], + "query": "from a_index | stats by bin(numberField, 5, 5, 5)", + "error": [], "warning": [] }, { - "query": "from a_index | where count_distinct(stringField, numberField) > 0", + "query": "from a_index | sort bucket(dateField, 1 year)", "error": [ - "WHERE does not support function count_distinct" + "SORT does not support function bucket" ], "warning": [] }, { - "query": "from a_index | eval var = count_distinct(stringField, numberField)", - "error": [ - "EVAL does not support function count_distinct" - ], + "query": "from a_index | stats bucket(null, null, null, null)", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = count_distinct(stringField, numberField) > 0", + "query": "row nullVar = null | stats bucket(nullVar, nullVar, nullVar, nullVar)", "error": [ - "EVAL does not support function count_distinct" + "Argument of [bucket] must be a constant, received [nullVar]", + "Argument of [bucket] must be a constant, received [nullVar]", + "Argument of [bucket] must be a constant, received [nullVar]" ], "warning": [] }, { - "query": "from a_index | eval count_distinct(stringField, numberField)", - "error": [ - "EVAL does not support function count_distinct" - ], + "query": "from a_index | stats bucket(\"2022\", 1 year)", + "error": [], "warning": [] }, { - "query": "from a_index | eval count_distinct(stringField, numberField) > 0", + "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 1 year)", "error": [ - "EVAL does not support function count_distinct" + "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" ], "warning": [] }, { - "query": "from a_index | stats count_distinct(null, null)", - "error": [], + "query": "from a_index | stats by bucket(concat(\"20\", \"22\"), 1 year)", + "error": [ + "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" + ], "warning": [] }, { - "query": "row nullVar = null | stats count_distinct(nullVar, nullVar)", + "query": "from a_index | stats bucket(\"2022\", 5, \"a\", \"a\")", "error": [], "warning": [] }, { - "query": "from a_index | stats var = st_centroid_agg(cartesianPointField)", - "error": [], + "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 5, \"a\", \"a\")", + "error": [ + "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" + ], "warning": [] }, { - "query": "from a_index | stats st_centroid_agg(cartesianPointField)", + "query": "from a_index | stats bucket(\"2022\", 5, \"2022\", \"2022\")", "error": [], "warning": [] }, { - "query": "from a_index | stats var = st_centroid_agg(avg(numberField))", - "error": [ - "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" - ], - "warning": [] - }, - { - "query": "from a_index | stats st_centroid_agg(avg(numberField))", + "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 5, concat(\"20\", \"22\"), concat(\"20\", \"22\"))", "error": [ - "Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [avg(numberField)] of type [number]" + "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" ], "warning": [] }, { - "query": "from a_index | stats st_centroid_agg(stringField)", - "error": [ - "Argument of [st_centroid_agg] must be [cartesian_point], found value [stringField] type [string]" - ], + "query": "from a_index | stats bucket(\"2022\", 5, \"a\", \"2022\")", + "error": [], "warning": [] }, { - "query": "from a_index | stats var = st_centroid_agg(*)", + "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 5, \"a\", concat(\"20\", \"22\"))", "error": [ - "Using wildcards (*) in st_centroid_agg is not allowed" + "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" ], "warning": [] }, { - "query": "from a_index | stats var = st_centroid_agg(geoPointField)", + "query": "from a_index | stats bucket(\"2022\", 5, \"2022\", \"a\")", "error": [], "warning": [] }, { - "query": "from a_index | stats st_centroid_agg(geoPointField)", - "error": [], + "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 5, concat(\"20\", \"22\"), \"a\")", + "error": [ + "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" + ], "warning": [] }, { - "query": "from a_index | sort st_centroid_agg(cartesianPointField)", - "error": [ - "SORT does not support function st_centroid_agg" - ], + "query": "row var = cbrt(5)", + "error": [], "warning": [] }, { - "query": "from a_index | where st_centroid_agg(cartesianPointField)", - "error": [ - "WHERE does not support function st_centroid_agg" - ], + "query": "row cbrt(5)", + "error": [], "warning": [] }, { - "query": "from a_index | where st_centroid_agg(cartesianPointField) > 0", - "error": [ - "WHERE does not support function st_centroid_agg" - ], + "query": "row var = cbrt(to_integer(true))", + "error": [], "warning": [] }, { - "query": "from a_index | where st_centroid_agg(geoPointField)", + "query": "row var = cbrt(true)", "error": [ - "WHERE does not support function st_centroid_agg" + "Argument of [cbrt] must be [number], found value [true] type [boolean]" ], "warning": [] }, { - "query": "from a_index | where st_centroid_agg(geoPointField) > 0", - "error": [ - "WHERE does not support function st_centroid_agg" - ], + "query": "from a_index | where cbrt(numberField) > 0", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = st_centroid_agg(cartesianPointField)", + "query": "from a_index | where cbrt(booleanField) > 0", "error": [ - "EVAL does not support function st_centroid_agg" + "Argument of [cbrt] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval var = st_centroid_agg(cartesianPointField) > 0", - "error": [ - "EVAL does not support function st_centroid_agg" - ], + "query": "from a_index | eval var = cbrt(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval st_centroid_agg(cartesianPointField)", - "error": [ - "EVAL does not support function st_centroid_agg" - ], + "query": "from a_index | eval cbrt(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval st_centroid_agg(cartesianPointField) > 0", - "error": [ - "EVAL does not support function st_centroid_agg" - ], + "query": "from a_index | eval var = cbrt(to_integer(booleanField))", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = st_centroid_agg(geoPointField)", + "query": "from a_index | eval cbrt(booleanField)", "error": [ - "EVAL does not support function st_centroid_agg" + "Argument of [cbrt] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval var = st_centroid_agg(geoPointField) > 0", + "query": "from a_index | eval var = cbrt(*)", "error": [ - "EVAL does not support function st_centroid_agg" + "Using wildcards (*) in cbrt is not allowed" ], "warning": [] }, { - "query": "from a_index | eval st_centroid_agg(geoPointField)", + "query": "from a_index | eval cbrt(numberField, extraArg)", "error": [ - "EVAL does not support function st_centroid_agg" + "Error: [cbrt] function expects exactly one argument, got 2." ], "warning": [] }, { - "query": "from a_index | eval st_centroid_agg(geoPointField) > 0", - "error": [ - "EVAL does not support function st_centroid_agg" - ], + "query": "from a_index | sort cbrt(numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | stats st_centroid_agg(booleanField)", - "error": [ - "Argument of [st_centroid_agg] must be [cartesian_point], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval cbrt(null)", + "error": [], "warning": [] }, { - "query": "from a_index | stats st_centroid_agg(null)", + "query": "row nullVar = null | eval cbrt(nullVar)", "error": [], "warning": [] }, { - "query": "row nullVar = null | stats st_centroid_agg(nullVar)", + "query": "row var = from_base64(\"a\")", "error": [], "warning": [] }, { - "query": "from a_index | stats var = values(stringField)", + "query": "row from_base64(\"a\")", "error": [], "warning": [] }, { - "query": "from a_index | stats values(stringField)", + "query": "row var = from_base64(to_string(true))", "error": [], "warning": [] }, { - "query": "from a_index | sort values(stringField)", + "query": "row var = from_base64(true)", "error": [ - "SORT does not support function values" + "Argument of [from_base64] must be [string], found value [true] type [boolean]" ], "warning": [] }, { - "query": "from a_index | where values(stringField)", - "error": [ - "WHERE does not support function values" - ], + "query": "from a_index | where length(from_base64(stringField)) > 0", + "error": [], "warning": [] }, { - "query": "from a_index | where values(stringField) > 0", + "query": "from a_index | where length(from_base64(booleanField)) > 0", "error": [ - "WHERE does not support function values" + "Argument of [from_base64] must be [string], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval var = values(stringField)", - "error": [ - "EVAL does not support function values" - ], + "query": "from a_index | eval var = from_base64(stringField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = values(stringField) > 0", + "query": "from a_index | eval from_base64(stringField)", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval var = from_base64(to_string(booleanField))", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval from_base64(booleanField)", "error": [ - "EVAL does not support function values" + "Argument of [from_base64] must be [string], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval values(stringField)", + "query": "from a_index | eval var = from_base64(*)", "error": [ - "EVAL does not support function values" + "Using wildcards (*) in from_base64 is not allowed" ], "warning": [] }, { - "query": "from a_index | eval values(stringField) > 0", + "query": "from a_index | eval from_base64(stringField, extraArg)", "error": [ - "EVAL does not support function values" + "Error: [from_base64] function expects exactly one argument, got 2." ], "warning": [] }, { - "query": "from a_index | stats values(null)", + "query": "from a_index | sort from_base64(stringField)", "error": [], "warning": [] }, { - "query": "row nullVar = null | stats values(nullVar)", + "query": "from a_index | eval from_base64(null)", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(dateField, 1 year)", + "query": "row nullVar = null | eval from_base64(nullVar)", "error": [], "warning": [] }, { - "query": "from a_index | stats by bin(dateField, 1 year)", + "query": "row var = locate(\"a\", \"a\")", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(numberField, 5)", + "query": "row locate(\"a\", \"a\")", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(numberField, numberField)", - "error": [ - "Argument of [bucket] must be a constant, received [numberField]" - ], + "query": "row var = locate(to_string(true), to_string(true))", + "error": [], "warning": [] }, { - "query": "from a_index | stats by bin(numberField, 5)", + "query": "row var = locate(\"a\", \"a\", 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(dateField, 5, \"a\", \"a\")", + "query": "row locate(\"a\", \"a\", 5)", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(dateField, numberField, stringField, stringField)", - "error": [ - "Argument of [bucket] must be a constant, received [numberField]", - "Argument of [bucket] must be a constant, received [stringField]", - "Argument of [bucket] must be a constant, received [stringField]" - ], + "query": "row var = locate(to_string(true), to_string(true), to_integer(true))", + "error": [], "warning": [] }, { - "query": "from a_index | stats by bin(dateField, 5, \"a\", \"a\")", - "error": [], + "query": "row var = locate(true, true, true)", + "error": [ + "Argument of [locate] must be [string], found value [true] type [boolean]", + "Argument of [locate] must be [string], found value [true] type [boolean]", + "Argument of [locate] must be [number], found value [true] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | stats by bucket(dateField, 5, now(), now())", + "query": "from a_index | where locate(stringField, stringField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(dateField, numberField, dateField, dateField)", + "query": "from a_index | where locate(booleanField, booleanField) > 0", "error": [ - "Argument of [bucket] must be a constant, received [numberField]", - "Argument of [bucket] must be a constant, received [dateField]", - "Argument of [bucket] must be a constant, received [dateField]" + "Argument of [locate] must be [string], found value [booleanField] type [boolean]", + "Argument of [locate] must be [string], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | stats by bin(dateField, 5, now(), now())", + "query": "from a_index | where locate(stringField, stringField, numberField) > 0", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(dateField, 5, \"a\", now())", - "error": [], + "query": "from a_index | where locate(booleanField, booleanField, booleanField) > 0", + "error": [ + "Argument of [locate] must be [string], found value [booleanField] type [boolean]", + "Argument of [locate] must be [string], found value [booleanField] type [boolean]", + "Argument of [locate] must be [number], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "from a_index | stats by bucket(dateField, numberField, stringField, dateField)", - "error": [ - "Argument of [bucket] must be a constant, received [numberField]", - "Argument of [bucket] must be a constant, received [stringField]", - "Argument of [bucket] must be a constant, received [dateField]" - ], + "query": "from a_index | eval var = locate(stringField, stringField)", + "error": [], "warning": [] }, { - "query": "from a_index | stats by bin(dateField, 5, \"a\", now())", + "query": "from a_index | eval locate(stringField, stringField)", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(dateField, 5, now(), \"a\")", + "query": "from a_index | eval var = locate(to_string(booleanField), to_string(booleanField))", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(dateField, numberField, dateField, stringField)", + "query": "from a_index | eval locate(booleanField, booleanField)", "error": [ - "Argument of [bucket] must be a constant, received [numberField]", - "Argument of [bucket] must be a constant, received [dateField]", - "Argument of [bucket] must be a constant, received [stringField]" + "Argument of [locate] must be [string], found value [booleanField] type [boolean]", + "Argument of [locate] must be [string], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | stats by bin(dateField, 5, now(), \"a\")", + "query": "from a_index | eval var = locate(stringField, stringField, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(numberField, 5, 5, 5)", + "query": "from a_index | eval locate(stringField, stringField, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(numberField, numberField, numberField, numberField)", + "query": "from a_index | eval var = locate(to_string(booleanField), to_string(booleanField), to_integer(booleanField))", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval locate(booleanField, booleanField, booleanField)", "error": [ - "Argument of [bucket] must be a constant, received [numberField]", - "Argument of [bucket] must be a constant, received [numberField]", - "Argument of [bucket] must be a constant, received [numberField]" + "Argument of [locate] must be [string], found value [booleanField] type [boolean]", + "Argument of [locate] must be [string], found value [booleanField] type [boolean]", + "Argument of [locate] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | stats by bin(numberField, 5, 5, 5)", + "query": "from a_index | eval locate(stringField, stringField, numberField, extraArg)", + "error": [ + "Error: [locate] function expects no more than 3 arguments, got 4." + ], + "warning": [] + }, + { + "query": "from a_index | sort locate(stringField, stringField)", "error": [], "warning": [] }, { - "query": "from a_index | sort bucket(dateField, 1 year)", - "error": [ - "SORT does not support function bucket" - ], + "query": "from a_index | eval locate(null, null, null)", + "error": [], "warning": [] }, { - "query": "from a_index | stats bucket(null, null, null, null)", + "query": "row nullVar = null | eval locate(nullVar, nullVar, nullVar)", "error": [], "warning": [] }, { - "query": "row nullVar = null | stats bucket(nullVar, nullVar, nullVar, nullVar)", - "error": [ - "Argument of [bucket] must be a constant, received [nullVar]", - "Argument of [bucket] must be a constant, received [nullVar]", - "Argument of [bucket] must be a constant, received [nullVar]" - ], + "query": "row var = to_base64(\"a\")", + "error": [], "warning": [] }, { - "query": "from a_index | stats bucket(\"2022\", 1 year)", + "query": "row to_base64(\"a\")", "error": [], "warning": [] }, { - "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 1 year)", - "error": [ - "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" - ], + "query": "row var = to_base64(to_string(true))", + "error": [], "warning": [] }, { - "query": "from a_index | stats by bucket(concat(\"20\", \"22\"), 1 year)", + "query": "row var = to_base64(true)", "error": [ - "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" + "Argument of [to_base64] must be [string], found value [true] type [boolean]" ], "warning": [] }, { - "query": "from a_index | stats bucket(\"2022\", 5, \"a\", \"a\")", + "query": "from a_index | where length(to_base64(stringField)) > 0", "error": [], "warning": [] }, { - "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 5, \"a\", \"a\")", + "query": "from a_index | where length(to_base64(booleanField)) > 0", "error": [ - "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" + "Argument of [to_base64] must be [string], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | stats bucket(\"2022\", 5, \"2022\", \"2022\")", + "query": "from a_index | eval var = to_base64(stringField)", "error": [], "warning": [] }, { - "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 5, concat(\"20\", \"22\"), concat(\"20\", \"22\"))", - "error": [ - "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" - ], + "query": "from a_index | eval to_base64(stringField)", + "error": [], "warning": [] }, { - "query": "from a_index | stats bucket(\"2022\", 5, \"a\", \"2022\")", + "query": "from a_index | eval var = to_base64(to_string(booleanField))", "error": [], "warning": [] }, { - "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 5, \"a\", concat(\"20\", \"22\"))", + "query": "from a_index | eval to_base64(booleanField)", "error": [ - "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" + "Argument of [to_base64] must be [string], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | stats bucket(\"2022\", 5, \"2022\", \"a\")", - "error": [], + "query": "from a_index | eval var = to_base64(*)", + "error": [ + "Using wildcards (*) in to_base64 is not allowed" + ], "warning": [] }, { - "query": "from a_index | stats bucket(concat(\"20\", \"22\"), 5, concat(\"20\", \"22\"), \"a\")", + "query": "from a_index | eval to_base64(stringField, extraArg)", "error": [ - "Argument of [bucket] must be [date], found value [concat(\"20\", \"22\")] type [string]" + "Error: [to_base64] function expects exactly one argument, got 2." ], "warning": [] }, { - "query": "row var = cbrt(5)", + "query": "from a_index | sort to_base64(stringField)", "error": [], "warning": [] }, { - "query": "row cbrt(5)", + "query": "from a_index | eval to_base64(null)", "error": [], "warning": [] }, { - "query": "row var = cbrt(to_integer(true))", + "query": "row nullVar = null | eval to_base64(nullVar)", "error": [], "warning": [] }, { - "query": "row var = cbrt(true)", - "error": [ - "Argument of [cbrt] must be [number], found value [true] type [boolean]" - ], + "query": "row var = ip_prefix(to_ip(\"127.0.0.1\"), 5, 5)", + "error": [], "warning": [] }, { - "query": "from a_index | where cbrt(numberField) > 0", + "query": "row ip_prefix(to_ip(\"127.0.0.1\"), 5, 5)", "error": [], "warning": [] }, { - "query": "from a_index | where cbrt(booleanField) > 0", + "query": "row var = ip_prefix(to_ip(to_ip(\"127.0.0.1\")), to_integer(true), to_integer(true))", + "error": [], + "warning": [] + }, + { + "query": "row var = ip_prefix(true, true, true)", "error": [ - "Argument of [cbrt] must be [number], found value [booleanField] type [boolean]" + "Argument of [ip_prefix] must be [ip], found value [true] type [boolean]", + "Argument of [ip_prefix] must be [number], found value [true] type [boolean]", + "Argument of [ip_prefix] must be [number], found value [true] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval var = cbrt(numberField)", + "query": "from a_index | eval var = ip_prefix(ipField, numberField, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval cbrt(numberField)", + "query": "from a_index | eval ip_prefix(ipField, numberField, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = cbrt(to_integer(booleanField))", + "query": "from a_index | eval var = ip_prefix(to_ip(ipField), to_integer(booleanField), to_integer(booleanField))", "error": [], "warning": [] }, { - "query": "from a_index | eval cbrt(booleanField)", + "query": "from a_index | eval ip_prefix(booleanField, booleanField, booleanField)", "error": [ - "Argument of [cbrt] must be [number], found value [booleanField] type [boolean]" + "Argument of [ip_prefix] must be [ip], found value [booleanField] type [boolean]", + "Argument of [ip_prefix] must be [number], found value [booleanField] type [boolean]", + "Argument of [ip_prefix] must be [number], found value [booleanField] type [boolean]" ], "warning": [] }, { - "query": "from a_index | eval var = cbrt(*)", + "query": "from a_index | eval ip_prefix(ipField, numberField, numberField, extraArg)", "error": [ - "Using wildcards (*) in cbrt is not allowed" + "Error: [ip_prefix] function expects exactly 3 arguments, got 4." ], "warning": [] }, { - "query": "from a_index | eval cbrt(numberField, extraArg)", - "error": [ - "Error: [cbrt] function expects exactly one argument, got 2." - ], + "query": "from a_index | sort ip_prefix(ipField, numberField, numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | sort cbrt(numberField)", + "query": "from a_index | eval ip_prefix(null, null, null)", "error": [], "warning": [] }, { - "query": "from a_index | eval cbrt(null)", + "query": "row nullVar = null | eval ip_prefix(nullVar, nullVar, nullVar)", "error": [], "warning": [] }, { - "query": "row nullVar = null | eval cbrt(nullVar)", + "query": "row var = mv_append(true, true)", "error": [], "warning": [] }, { - "query": "row var = from_base64(\"a\")", + "query": "row mv_append(true, true)", "error": [], "warning": [] }, { - "query": "row from_base64(\"a\")", + "query": "row var = mv_append(to_boolean(true), to_boolean(true))", "error": [], "warning": [] }, { - "query": "row var = from_base64(to_string(true))", + "query": "row var = mv_append(to_cartesianpoint(\"POINT (30 10)\"), to_cartesianpoint(\"POINT (30 10)\"))", "error": [], "warning": [] }, { - "query": "row var = from_base64(true)", - "error": [ - "Argument of [from_base64] must be [string], found value [true] type [boolean]" - ], + "query": "row mv_append(to_cartesianpoint(\"POINT (30 10)\"), to_cartesianpoint(\"POINT (30 10)\"))", + "error": [], "warning": [] }, { - "query": "from a_index | where length(from_base64(stringField)) > 0", + "query": "row var = mv_append(to_cartesianpoint(to_cartesianpoint(\"POINT (30 10)\")), to_cartesianpoint(to_cartesianpoint(\"POINT (30 10)\")))", "error": [], "warning": [] }, { - "query": "from a_index | where length(from_base64(booleanField)) > 0", - "error": [ - "Argument of [from_base64] must be [string], found value [booleanField] type [boolean]" - ], + "query": "row var = mv_append(to_cartesianshape(\"POINT (30 10)\"), to_cartesianshape(\"POINT (30 10)\"))", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = from_base64(stringField)", + "query": "row mv_append(to_cartesianshape(\"POINT (30 10)\"), to_cartesianshape(\"POINT (30 10)\"))", "error": [], "warning": [] }, { - "query": "from a_index | eval from_base64(stringField)", + "query": "row var = mv_append(to_cartesianshape(to_cartesianpoint(\"POINT (30 10)\")), to_cartesianshape(to_cartesianpoint(\"POINT (30 10)\")))", "error": [], "warning": [] }, { - "query": "from a_index | eval var = from_base64(to_string(booleanField))", + "query": "row var = mv_append(now(), now())", "error": [], "warning": [] }, { - "query": "from a_index | eval from_base64(booleanField)", - "error": [ - "Argument of [from_base64] must be [string], found value [booleanField] type [boolean]" - ], + "query": "row mv_append(now(), now())", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = from_base64(*)", - "error": [ - "Using wildcards (*) in from_base64 is not allowed" - ], + "query": "row var = mv_append(to_datetime(now()), to_datetime(now()))", + "error": [], "warning": [] }, { - "query": "from a_index | eval from_base64(stringField, extraArg)", - "error": [ - "Error: [from_base64] function expects exactly one argument, got 2." - ], + "query": "row var = mv_append(5, 5)", + "error": [], "warning": [] }, { - "query": "from a_index | sort from_base64(stringField)", + "query": "row mv_append(5, 5)", "error": [], "warning": [] }, { - "query": "from a_index | eval from_base64(null)", + "query": "row var = mv_append(to_integer(true), to_integer(true))", "error": [], "warning": [] }, { - "query": "row nullVar = null | eval from_base64(nullVar)", + "query": "row var = mv_append(to_geopoint(\"POINT (30 10)\"), to_geopoint(\"POINT (30 10)\"))", "error": [], "warning": [] }, { - "query": "row var = locate(\"a\", \"a\")", + "query": "row mv_append(to_geopoint(\"POINT (30 10)\"), to_geopoint(\"POINT (30 10)\"))", "error": [], "warning": [] }, { - "query": "row locate(\"a\", \"a\")", + "query": "row var = mv_append(to_geopoint(to_geopoint(\"POINT (30 10)\")), to_geopoint(to_geopoint(\"POINT (30 10)\")))", "error": [], "warning": [] }, { - "query": "row var = locate(to_string(true), to_string(true))", + "query": "row var = mv_append(to_geoshape(\"POINT (30 10)\"), to_geoshape(\"POINT (30 10)\"))", "error": [], "warning": [] }, { - "query": "row var = locate(\"a\", \"a\", 5)", + "query": "row mv_append(to_geoshape(\"POINT (30 10)\"), to_geoshape(\"POINT (30 10)\"))", "error": [], "warning": [] }, { - "query": "row locate(\"a\", \"a\", 5)", + "query": "row var = mv_append(to_geoshape(to_geopoint(\"POINT (30 10)\")), to_geoshape(to_geopoint(\"POINT (30 10)\")))", "error": [], "warning": [] }, { - "query": "row var = locate(to_string(true), to_string(true), to_integer(true))", + "query": "row var = mv_append(to_ip(\"127.0.0.1\"), to_ip(\"127.0.0.1\"))", "error": [], "warning": [] }, { - "query": "row var = locate(true, true, true)", - "error": [ - "Argument of [locate] must be [string], found value [true] type [boolean]", - "Argument of [locate] must be [string], found value [true] type [boolean]", - "Argument of [locate] must be [number], found value [true] type [boolean]" - ], + "query": "row mv_append(to_ip(\"127.0.0.1\"), to_ip(\"127.0.0.1\"))", + "error": [], "warning": [] }, { - "query": "from a_index | where locate(stringField, stringField) > 0", + "query": "row var = mv_append(to_ip(to_ip(\"127.0.0.1\")), to_ip(to_ip(\"127.0.0.1\")))", "error": [], "warning": [] }, { - "query": "from a_index | where locate(booleanField, booleanField) > 0", - "error": [ - "Argument of [locate] must be [string], found value [booleanField] type [boolean]", - "Argument of [locate] must be [string], found value [booleanField] type [boolean]" - ], + "query": "row var = mv_append(\"a\", \"a\")", + "error": [], "warning": [] }, { - "query": "from a_index | where locate(stringField, stringField, numberField) > 0", + "query": "row mv_append(\"a\", \"a\")", "error": [], "warning": [] }, { - "query": "from a_index | where locate(booleanField, booleanField, booleanField) > 0", - "error": [ - "Argument of [locate] must be [string], found value [booleanField] type [boolean]", - "Argument of [locate] must be [string], found value [booleanField] type [boolean]", - "Argument of [locate] must be [number], found value [booleanField] type [boolean]" - ], + "query": "row var = mv_append(to_string(true), to_string(true))", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = locate(stringField, stringField)", + "query": "row var = mv_append(to_version(\"1.0.0\"), to_version(\"1.0.0\"))", "error": [], "warning": [] }, { - "query": "from a_index | eval locate(stringField, stringField)", + "query": "row mv_append(to_version(\"1.0.0\"), to_version(\"1.0.0\"))", "error": [], "warning": [] }, { - "query": "from a_index | eval var = locate(to_string(booleanField), to_string(booleanField))", + "query": "row var = mv_append(to_version(\"a\"), to_version(\"a\"))", "error": [], "warning": [] }, { - "query": "from a_index | eval locate(booleanField, booleanField)", - "error": [ - "Argument of [locate] must be [string], found value [booleanField] type [boolean]", - "Argument of [locate] must be [string], found value [booleanField] type [boolean]" - ], + "query": "from a_index | where mv_append(numberField, numberField) > 0", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = locate(stringField, stringField, numberField)", + "query": "from a_index | where length(mv_append(stringField, stringField)) > 0", "error": [], "warning": [] }, { - "query": "from a_index | eval locate(stringField, stringField, numberField)", + "query": "from a_index | eval var = mv_append(booleanField, booleanField)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = locate(to_string(booleanField), to_string(booleanField), to_integer(booleanField))", + "query": "from a_index | eval mv_append(booleanField, booleanField)", "error": [], "warning": [] }, { - "query": "from a_index | eval locate(booleanField, booleanField, booleanField)", - "error": [ - "Argument of [locate] must be [string], found value [booleanField] type [boolean]", - "Argument of [locate] must be [string], found value [booleanField] type [boolean]", - "Argument of [locate] must be [number], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval var = mv_append(to_boolean(booleanField), to_boolean(booleanField))", + "error": [], "warning": [] }, { - "query": "from a_index | eval locate(stringField, stringField, numberField, extraArg)", - "error": [ - "Error: [locate] function expects no more than 3 arguments, got 4." - ], + "query": "from a_index | eval var = mv_append(cartesianPointField, cartesianPointField)", + "error": [], "warning": [] }, { - "query": "from a_index | sort locate(stringField, stringField)", + "query": "from a_index | eval mv_append(cartesianPointField, cartesianPointField)", "error": [], "warning": [] }, { - "query": "from a_index | eval locate(null, null, null)", + "query": "from a_index | eval var = mv_append(to_cartesianpoint(cartesianPointField), to_cartesianpoint(cartesianPointField))", "error": [], "warning": [] }, { - "query": "row nullVar = null | eval locate(nullVar, nullVar, nullVar)", + "query": "from a_index | eval var = mv_append(cartesianShapeField, cartesianShapeField)", "error": [], "warning": [] }, { - "query": "row var = to_base64(\"a\")", + "query": "from a_index | eval mv_append(cartesianShapeField, cartesianShapeField)", "error": [], "warning": [] }, { - "query": "row to_base64(\"a\")", + "query": "from a_index | eval var = mv_append(to_cartesianshape(cartesianPointField), to_cartesianshape(cartesianPointField))", "error": [], "warning": [] }, { - "query": "row var = to_base64(to_string(true))", + "query": "from a_index | eval var = mv_append(dateField, dateField)", "error": [], "warning": [] }, { - "query": "row var = to_base64(true)", - "error": [ - "Argument of [to_base64] must be [string], found value [true] type [boolean]" - ], + "query": "from a_index | eval mv_append(dateField, dateField)", + "error": [], "warning": [] }, { - "query": "from a_index | where length(to_base64(stringField)) > 0", + "query": "from a_index | eval var = mv_append(to_datetime(dateField), to_datetime(dateField))", "error": [], "warning": [] }, { - "query": "from a_index | where length(to_base64(booleanField)) > 0", - "error": [ - "Argument of [to_base64] must be [string], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval var = mv_append(numberField, numberField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = to_base64(stringField)", + "query": "from a_index | eval mv_append(numberField, numberField)", "error": [], "warning": [] }, { - "query": "from a_index | eval to_base64(stringField)", + "query": "from a_index | eval var = mv_append(to_integer(booleanField), to_integer(booleanField))", "error": [], "warning": [] }, { - "query": "from a_index | eval var = to_base64(to_string(booleanField))", + "query": "from a_index | eval var = mv_append(geoPointField, geoPointField)", "error": [], "warning": [] }, { - "query": "from a_index | eval to_base64(booleanField)", - "error": [ - "Argument of [to_base64] must be [string], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval mv_append(geoPointField, geoPointField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = to_base64(*)", - "error": [ - "Using wildcards (*) in to_base64 is not allowed" - ], + "query": "from a_index | eval var = mv_append(to_geopoint(geoPointField), to_geopoint(geoPointField))", + "error": [], "warning": [] }, { - "query": "from a_index | eval to_base64(stringField, extraArg)", - "error": [ - "Error: [to_base64] function expects exactly one argument, got 2." - ], + "query": "from a_index | eval var = mv_append(geoShapeField, geoShapeField)", + "error": [], "warning": [] }, { - "query": "from a_index | sort to_base64(stringField)", + "query": "from a_index | eval mv_append(geoShapeField, geoShapeField)", "error": [], "warning": [] }, { - "query": "from a_index | eval to_base64(null)", + "query": "from a_index | eval var = mv_append(to_geoshape(geoPointField), to_geoshape(geoPointField))", "error": [], "warning": [] }, { - "query": "row nullVar = null | eval to_base64(nullVar)", + "query": "from a_index | eval var = mv_append(ipField, ipField)", "error": [], "warning": [] }, { - "query": "row var = ip_prefix(to_ip(\"127.0.0.1\"), 5, 5)", + "query": "from a_index | eval mv_append(ipField, ipField)", "error": [], "warning": [] }, { - "query": "row ip_prefix(to_ip(\"127.0.0.1\"), 5, 5)", + "query": "from a_index | eval var = mv_append(to_ip(ipField), to_ip(ipField))", "error": [], "warning": [] }, { - "query": "row var = ip_prefix(to_ip(to_ip(\"127.0.0.1\")), to_integer(true), to_integer(true))", + "query": "from a_index | eval var = mv_append(stringField, stringField)", "error": [], "warning": [] }, { - "query": "row var = ip_prefix(true, true, true)", - "error": [ - "Argument of [ip_prefix] must be [ip], found value [true] type [boolean]", - "Argument of [ip_prefix] must be [number], found value [true] type [boolean]", - "Argument of [ip_prefix] must be [number], found value [true] type [boolean]" - ], + "query": "from a_index | eval mv_append(stringField, stringField)", + "error": [], "warning": [] }, { - "query": "from a_index | eval var = ip_prefix(ipField, numberField, numberField)", + "query": "from a_index | eval var = mv_append(to_string(booleanField), to_string(booleanField))", "error": [], "warning": [] }, { - "query": "from a_index | eval ip_prefix(ipField, numberField, numberField)", + "query": "from a_index | eval var = mv_append(versionField, versionField)", "error": [], "warning": [] }, { - "query": "from a_index | eval var = ip_prefix(to_ip(ipField), to_integer(booleanField), to_integer(booleanField))", + "query": "from a_index | eval mv_append(versionField, versionField)", "error": [], "warning": [] }, { - "query": "from a_index | eval ip_prefix(booleanField, booleanField, booleanField)", - "error": [ - "Argument of [ip_prefix] must be [ip], found value [booleanField] type [boolean]", - "Argument of [ip_prefix] must be [number], found value [booleanField] type [boolean]", - "Argument of [ip_prefix] must be [number], found value [booleanField] type [boolean]" - ], + "query": "from a_index | eval var = mv_append(to_version(stringField), to_version(stringField))", + "error": [], "warning": [] }, { - "query": "from a_index | eval ip_prefix(ipField, numberField, numberField, extraArg)", + "query": "from a_index | eval mv_append(booleanField, booleanField, extraArg)", "error": [ - "Error: [ip_prefix] function expects exactly 3 arguments, got 4." + "Error: [mv_append] function expects exactly 2 arguments, got 3." ], "warning": [] }, { - "query": "from a_index | sort ip_prefix(ipField, numberField, numberField)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval ip_prefix(null, null, null)", - "error": [], - "warning": [] - }, - { - "query": "row nullVar = null | eval ip_prefix(nullVar, nullVar, nullVar)", + "query": "from a_index | sort mv_append(booleanField, booleanField)", "error": [], "warning": [] }, { - "query": "row var = mv_append(true, true)", + "query": "from a_index | eval mv_append(null, null)", "error": [], "warning": [] }, { - "query": "row mv_append(true, true)", + "query": "row nullVar = null | eval mv_append(nullVar, nullVar)", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_boolean(true), to_boolean(true))", + "query": "row var = repeat(\"a\", 5)", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_cartesianpoint(\"POINT (30 10)\"), to_cartesianpoint(\"POINT (30 10)\"))", + "query": "row repeat(\"a\", 5)", "error": [], "warning": [] }, { - "query": "row mv_append(to_cartesianpoint(\"POINT (30 10)\"), to_cartesianpoint(\"POINT (30 10)\"))", + "query": "row var = repeat(to_string(true), to_integer(true))", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_cartesianpoint(to_cartesianpoint(\"POINT (30 10)\")), to_cartesianpoint(to_cartesianpoint(\"POINT (30 10)\")))", - "error": [], + "query": "row var = repeat(true, true)", + "error": [ + "Argument of [repeat] must be [string], found value [true] type [boolean]", + "Argument of [repeat] must be [number], found value [true] type [boolean]" + ], "warning": [] }, { - "query": "row var = mv_append(to_cartesianshape(\"POINT (30 10)\"), to_cartesianshape(\"POINT (30 10)\"))", + "query": "from a_index | where length(repeat(stringField, numberField)) > 0", "error": [], "warning": [] }, { - "query": "row mv_append(to_cartesianshape(\"POINT (30 10)\"), to_cartesianshape(\"POINT (30 10)\"))", - "error": [], + "query": "from a_index | where length(repeat(booleanField, booleanField)) > 0", + "error": [ + "Argument of [repeat] must be [string], found value [booleanField] type [boolean]", + "Argument of [repeat] must be [number], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "row var = mv_append(to_cartesianshape(to_cartesianpoint(\"POINT (30 10)\")), to_cartesianshape(to_cartesianpoint(\"POINT (30 10)\")))", + "query": "from a_index | eval var = repeat(stringField, numberField)", "error": [], "warning": [] }, { - "query": "row var = mv_append(now(), now())", + "query": "from a_index | eval repeat(stringField, numberField)", "error": [], "warning": [] }, { - "query": "row mv_append(now(), now())", + "query": "from a_index | eval var = repeat(to_string(booleanField), to_integer(booleanField))", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_datetime(now()), to_datetime(now()))", - "error": [], + "query": "from a_index | eval repeat(booleanField, booleanField)", + "error": [ + "Argument of [repeat] must be [string], found value [booleanField] type [boolean]", + "Argument of [repeat] must be [number], found value [booleanField] type [boolean]" + ], "warning": [] }, { - "query": "row var = mv_append(5, 5)", - "error": [], + "query": "from a_index | eval repeat(stringField, numberField, extraArg)", + "error": [ + "Error: [repeat] function expects exactly 2 arguments, got 3." + ], "warning": [] }, { - "query": "row mv_append(5, 5)", + "query": "from a_index | sort repeat(stringField, numberField)", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_integer(true), to_integer(true))", + "query": "from a_index | eval repeat(null, null)", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_geopoint(\"POINT (30 10)\"), to_geopoint(\"POINT (30 10)\"))", + "query": "row nullVar = null | eval repeat(nullVar, nullVar)", "error": [], "warning": [] }, { - "query": "row mv_append(to_geopoint(\"POINT (30 10)\"), to_geopoint(\"POINT (30 10)\"))", - "error": [], + "query": "f", + "error": [ + "SyntaxError: mismatched input 'f' expecting {'explain', 'from', 'meta', 'metrics', 'row', 'show'}" + ], "warning": [] }, { - "query": "row var = mv_append(to_geopoint(to_geopoint(\"POINT (30 10)\")), to_geopoint(to_geopoint(\"POINT (30 10)\")))", - "error": [], + "query": "from ", + "error": [ + "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''" + ], "warning": [] }, { - "query": "row var = mv_append(to_geoshape(\"POINT (30 10)\"), to_geoshape(\"POINT (30 10)\"))", + "query": "from index", "error": [], "warning": [] }, { - "query": "row mv_append(to_geoshape(\"POINT (30 10)\"), to_geoshape(\"POINT (30 10)\"))", + "query": "FROM index", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_geoshape(to_geopoint(\"POINT (30 10)\")), to_geoshape(to_geopoint(\"POINT (30 10)\")))", + "query": "FrOm index", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_ip(\"127.0.0.1\"), to_ip(\"127.0.0.1\"))", + "query": "from index, other_index", "error": [], "warning": [] }, { - "query": "row mv_append(to_ip(\"127.0.0.1\"), to_ip(\"127.0.0.1\"))", + "query": "from index, other_index,.secret_index", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_ip(to_ip(\"127.0.0.1\")), to_ip(to_ip(\"127.0.0.1\")))", + "query": "from .secret_index", "error": [], "warning": [] }, { - "query": "row var = mv_append(\"a\", \"a\")", + "query": "from .secret_index", "error": [], "warning": [] }, { - "query": "row mv_append(\"a\", \"a\")", + "query": "from .secret_index", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_string(true), to_string(true))", + "query": "from ind*, other*", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_version(\"1.0.0\"), to_version(\"1.0.0\"))", + "query": "from index*", "error": [], "warning": [] }, { - "query": "row mv_append(to_version(\"1.0.0\"), to_version(\"1.0.0\"))", + "query": "FROM *a_i*dex*", "error": [], "warning": [] }, { - "query": "row var = mv_append(to_version(\"a\"), to_version(\"a\"))", + "query": "FROM in*ex*", "error": [], "warning": [] }, { - "query": "from a_index | where mv_append(numberField, numberField) > 0", + "query": "FROM *n*ex", "error": [], "warning": [] }, { - "query": "from a_index | where length(mv_append(stringField, stringField)) > 0", + "query": "FROM *n*ex*", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(booleanField, booleanField)", + "query": "FROM i*d*x*", "error": [], "warning": [] }, { - "query": "from a_index | eval mv_append(booleanField, booleanField)", + "query": "FROM i*d*x", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_boolean(booleanField), to_boolean(booleanField))", + "query": "FROM i***x*", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(cartesianPointField, cartesianPointField)", + "query": "FROM i****", "error": [], "warning": [] }, { - "query": "from a_index | eval mv_append(cartesianPointField, cartesianPointField)", + "query": "FROM i**", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_cartesianpoint(cartesianPointField), to_cartesianpoint(cartesianPointField))", + "query": "fRoM index**", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(cartesianShapeField, cartesianShapeField)", + "query": "fRoM *ex", "error": [], "warning": [] }, { - "query": "from a_index | eval mv_append(cartesianShapeField, cartesianShapeField)", + "query": "fRoM *ex*", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_cartesianshape(cartesianPointField), to_cartesianshape(cartesianPointField))", + "query": "fRoM in*ex", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(dateField, dateField)", + "query": "fRoM ind*ex", "error": [], "warning": [] }, { - "query": "from a_index | eval mv_append(dateField, dateField)", + "query": "fRoM *,-.*", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_datetime(dateField), to_datetime(dateField))", + "query": "fRoM remote-*:indexes*", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(numberField, numberField)", + "query": "fRoM remote-*:indexes", "error": [], "warning": [] }, { - "query": "from a_index | eval mv_append(numberField, numberField)", + "query": "fRoM remote-ccs:indexes", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_integer(booleanField), to_integer(booleanField))", + "query": "fRoM a_index, remote-ccs:indexes", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(geoPointField, geoPointField)", + "query": "fRoM .secret_index", "error": [], "warning": [] }, { - "query": "from a_index | eval mv_append(geoPointField, geoPointField)", + "query": "from my-index", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_geopoint(geoPointField), to_geopoint(geoPointField))", - "error": [], + "query": "from index,", + "error": [ + "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''" + ], "warning": [] }, { - "query": "from a_index | eval var = mv_append(geoShapeField, geoShapeField)", - "error": [], + "query": "FROM index\n, \tother_index\t,\n \t ", + "error": [ + "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''" + ], "warning": [] }, { - "query": "from a_index | eval mv_append(geoShapeField, geoShapeField)", - "error": [], + "query": "from assignment = 1", + "error": [ + "SyntaxError: mismatched input '=' expecting ", + "Unknown index [assignment]" + ], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_geoshape(geoPointField), to_geoshape(geoPointField))", - "error": [], + "query": "FROM `index`", + "error": [ + "SyntaxError: token recognition error at: '`'", + "SyntaxError: token recognition error at: '`'" + ], "warning": [] }, { - "query": "from a_index | eval var = mv_append(ipField, ipField)", - "error": [], + "query": "from assignment = 1", + "error": [ + "SyntaxError: mismatched input '=' expecting ", + "Unknown index [assignment]" + ], "warning": [] }, { - "query": "from a_index | eval mv_append(ipField, ipField)", - "error": [], + "query": "FROM index, missingIndex", + "error": [ + "Unknown index [missingIndex]" + ], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_ip(ipField), to_ip(ipField))", - "error": [], + "query": "from average()", + "error": [ + "Unknown index [average()]" + ], "warning": [] }, { - "query": "from a_index | eval var = mv_append(stringField, stringField)", - "error": [], + "query": "fRom custom_function()", + "error": [ + "Unknown index [custom_function()]" + ], "warning": [] }, { - "query": "from a_index | eval mv_append(stringField, stringField)", - "error": [], + "query": "FROM indexes*", + "error": [ + "Unknown index [indexes*]" + ], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_string(booleanField), to_string(booleanField))", - "error": [], + "query": "from numberField", + "error": [ + "Unknown index [numberField]" + ], "warning": [] }, { - "query": "from a_index | eval var = mv_append(versionField, versionField)", - "error": [], + "query": "FROM policy", + "error": [ + "Unknown index [policy]" + ], "warning": [] }, { - "query": "from a_index | eval mv_append(versionField, versionField)", + "query": "from index metadata _id", "error": [], "warning": [] }, { - "query": "from a_index | eval var = mv_append(to_version(stringField), to_version(stringField))", + "query": "from index metadata _id, \t\n _index\n ", "error": [], "warning": [] }, { - "query": "from a_index | eval mv_append(booleanField, booleanField, extraArg)", + "query": "from index (metadata _id)", "error": [ - "Error: [mv_append] function expects exactly 2 arguments, got 3." + "SyntaxError: mismatched input '(metadata' expecting " ], "warning": [] }, { - "query": "from a_index | sort mv_append(booleanField, booleanField)", + "query": "from index [METADATA _id]", "error": [], "warning": [] }, { - "query": "from a_index | eval mv_append(null, null)", + "query": "from index [METADATA _id]", "error": [], - "warning": [] + "warning": [ + "Square brackets '[]' need to be removed from FROM METADATA declaration" + ] }, { - "query": "row nullVar = null | eval mv_append(nullVar, nullVar)", + "query": "from index [metadata _id]", "error": [], - "warning": [] + "warning": [ + "Square brackets '[]' need to be removed from FROM METADATA declaration" + ] }, { - "query": "row var = repeat(\"a\", 5)", + "query": "from index [METADATA _id, _source]", "error": [], - "warning": [] + "warning": [ + "Square brackets '[]' need to be removed from FROM METADATA declaration" + ] }, { - "query": "row repeat(\"a\", 5)", + "query": "from remote-ccs:indexes [METADATA _id]", "error": [], - "warning": [] + "warning": [ + "Square brackets '[]' need to be removed from FROM METADATA declaration" + ] }, { - "query": "row var = repeat(to_string(true), to_integer(true))", + "query": "from *:indexes [METADATA _id]", "error": [], - "warning": [] + "warning": [ + "Square brackets '[]' need to be removed from FROM METADATA declaration" + ] }, { - "query": "row var = repeat(true, true)", + "query": "from index [METADATA _id, _source2]", "error": [ - "Argument of [repeat] must be [string], found value [true] type [boolean]", - "Argument of [repeat] must be [number], found value [true] type [boolean]" + "Metadata field [_source2] is not available. Available metadata fields are: [_version, _id, _index, _source, _ignored]" ], - "warning": [] - }, - { - "query": "from a_index | where length(repeat(stringField, numberField)) > 0", - "error": [], - "warning": [] + "warning": [ + "Square brackets '[]' need to be removed from FROM METADATA declaration" + ] }, { - "query": "from a_index | where length(repeat(booleanField, booleanField)) > 0", + "query": "from index [metadata _id, _source] [METADATA _id2]", "error": [ - "Argument of [repeat] must be [string], found value [booleanField] type [boolean]", - "Argument of [repeat] must be [number], found value [booleanField] type [boolean]" + "SyntaxError: mismatched input '[' expecting " ], - "warning": [] + "warning": [ + "Square brackets '[]' need to be removed from FROM METADATA declaration" + ] }, { - "query": "from a_index | eval var = repeat(stringField, numberField)", + "query": "from index METADATA _id", "error": [], "warning": [] }, { - "query": "from a_index | eval repeat(stringField, numberField)", + "query": "from index METADATA _id", "error": [], "warning": [] }, { - "query": "from a_index | eval var = repeat(to_string(booleanField), to_integer(booleanField))", + "query": "from index metadata _id", "error": [], "warning": [] }, { - "query": "from a_index | eval repeat(booleanField, booleanField)", - "error": [ - "Argument of [repeat] must be [string], found value [booleanField] type [boolean]", - "Argument of [repeat] must be [number], found value [booleanField] type [boolean]" - ], + "query": "from index METADATA _id, _source", + "error": [], "warning": [] }, { - "query": "from a_index | eval repeat(stringField, numberField, extraArg)", - "error": [ - "Error: [repeat] function expects exactly 2 arguments, got 3." - ], + "query": "from remote-ccs:indexes METADATA _id", + "error": [], "warning": [] }, { - "query": "from a_index | sort repeat(stringField, numberField)", + "query": "from *:indexes METADATA _id", "error": [], "warning": [] }, { - "query": "from a_index | eval repeat(null, null)", - "error": [], + "query": "from index METADATA _id, _source2", + "error": [ + "Metadata field [_source2] is not available. Available metadata fields are: [_version, _id, _index, _source, _ignored]" + ], "warning": [] }, { - "query": "row nullVar = null | eval repeat(nullVar, nullVar)", - "error": [], + "query": "from index metadata _id, _source METADATA _id2", + "error": [ + "SyntaxError: mismatched input 'METADATA' expecting " + ], "warning": [] } ] diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/validation/helpers.ts index 20ec8990e18301..11cf5fd2d8f496 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/helpers.ts @@ -6,7 +6,13 @@ * Side Public License, v 1. */ -import type { ESQLAst, ESQLAstItem, ESQLMessage, ESQLSingleAstItem } from '@kbn/esql-ast'; +import type { + ESQLAst, + ESQLAstItem, + ESQLAstMetricsCommand, + ESQLMessage, + ESQLSingleAstItem, +} from '@kbn/esql-ast'; import { FunctionDefinition } from '../definitions/types'; import { getAllArrayTypes, getAllArrayValues } from '../shared/helpers'; import { getMessageFromId } from './errors'; @@ -14,8 +20,10 @@ import type { ESQLPolicy, ReferenceMaps } from './types'; export function buildQueryForFieldsFromSource(queryString: string, ast: ESQLAst) { const firstCommand = ast[0]; - if (firstCommand == null) { - return ''; + if (!firstCommand) return ''; + if (firstCommand.name === 'metrics') { + const metrics = firstCommand as ESQLAstMetricsCommand; + return `FROM ${metrics.sources.map((source) => source.name).join(', ')}`; } return queryString.substring(0, firstCommand.location.max + 1); } diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/types.ts b/packages/kbn-esql-validation-autocomplete/src/validation/types.ts index fbfb35818cac1f..4d9732c0b5b22c 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/types.ts @@ -167,6 +167,26 @@ export interface ValidationErrors { message: string; type: { value: string | number }; }; + noAggFunction: { + message: string; + type: { + commandName: string; + expression: string; + }; + }; + expressionNotAggClosed: { + message: string; + type: { + commandName: string; + expression: string; + }; + }; + aggInAggFunction: { + message: string; + type: { + nestedAgg: string; + }; + }; } export type ErrorTypes = keyof ValidationErrors; diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.from.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.from.test.ts deleted file mode 100644 index 1639800c446d86..00000000000000 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.from.test.ts +++ /dev/null @@ -1,49 +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 { getAstAndSyntaxErrors } from '@kbn/esql-ast'; -import { ESQLCallbacks } from '../shared/types'; -import { ValidationOptions } from './types'; -import { validateQuery } from './validation'; -import { getCallbackMocks } from '../__tests__/helpers'; - -const setup = async () => { - const callbacks = getCallbackMocks(); - const validate = async ( - query: string, - opts: ValidationOptions = {}, - cb: ESQLCallbacks = callbacks - ) => { - return await validateQuery(query, getAstAndSyntaxErrors, opts, cb); - }; - - return { - callbacks, - validate, - }; -}; - -test('does not load fields when validating only a single FROM, SHOW, ROW command', async () => { - const { validate, callbacks } = await setup(); - - await validate('FROM kib'); - await validate('FROM kibana_ecommerce METADATA _i'); - await validate('FROM kibana_ecommerce METADATA _id | '); - await validate('SHOW'); - await validate('ROW \t'); - - expect(callbacks.getFieldsFor.mock.calls.length).toBe(0); -}); - -test('loads fields with FROM source when commands after pipe present', async () => { - const { validate, callbacks } = await setup(); - - await validate('FROM kibana_ecommerce METADATA _id | eval'); - - expect(callbacks.getFieldsFor.mock.calls.length).toBe(1); -}); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index edbe2e839ee25a..86e8c216946f62 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -18,7 +18,6 @@ import capitalize from 'lodash/capitalize'; import { camelCase } from 'lodash'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; import { nonNullable } from '../shared/helpers'; -import { METADATA_FIELDS } from '../shared/constants'; import { FUNCTION_DESCRIBE_BLOCK_NAME } from './function_describe_block_name'; import { fields, @@ -28,6 +27,8 @@ import { policies, unsupported_field, } from '../__tests__/helpers'; +import { validationFromCommandTestSuite as runFromTestSuite } from './__tests__/test_suites/validation.command.from'; +import { Setup, setup } from './__tests__/helpers'; const NESTING_LEVELS = 4; const NESTED_DEPTHS = Array(NESTING_LEVELS) @@ -262,116 +263,28 @@ describe('validation logic', () => { ); }); - describe('from', () => { - testErrorsAndWarnings('f', [ - `SyntaxError: mismatched input 'f' expecting {'explain', 'from', 'meta', 'metrics', 'row', 'show'}`, - ]); - testErrorsAndWarnings(`from `, ["SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''"]); - testErrorsAndWarnings(`from index,`, [ - "SyntaxError: missing INDEX_UNQUOTED_IDENTIFIER at ''", - ]); - testErrorsAndWarnings(`from assignment = 1`, [ - "SyntaxError: mismatched input '=' expecting ", - 'Unknown index [assignment]', - ]); - testErrorsAndWarnings(`from index`, []); - testErrorsAndWarnings(`FROM index`, []); - testErrorsAndWarnings(`FrOm index`, []); - testErrorsAndWarnings('from `index`', [ - "SyntaxError: token recognition error at: '`'", - "SyntaxError: token recognition error at: '`'", - ]); - - testErrorsAndWarnings(`from index, other_index`, []); - testErrorsAndWarnings(`from index, missingIndex`, ['Unknown index [missingIndex]']); - testErrorsAndWarnings(`from fn()`, ['Unknown index [fn()]']); - testErrorsAndWarnings(`from average()`, ['Unknown index [average()]']); - for (const isWrapped of [true, false]) { - function setWrapping(option: string) { - return isWrapped ? `[${option}]` : option; - } - function addBracketsWarning() { - return isWrapped - ? ["Square brackets '[]' need to be removed from FROM METADATA declaration"] - : []; - } - testErrorsAndWarnings( - `from index ${setWrapping('METADATA _id')}`, - [], - addBracketsWarning() - ); - testErrorsAndWarnings( - `from index ${setWrapping('metadata _id')}`, - [], - addBracketsWarning() - ); - - testErrorsAndWarnings( - `from index ${setWrapping('METADATA _id, _source')}`, - [], - addBracketsWarning() - ); - testErrorsAndWarnings( - `from index ${setWrapping('METADATA _id, _source2')}`, - [ - `Metadata field [_source2] is not available. Available metadata fields are: [${METADATA_FIELDS.join( - ', ' - )}]`, - ], - addBracketsWarning() - ); - testErrorsAndWarnings( - `from index ${setWrapping('metadata _id, _source')} ${setWrapping('METADATA _id2')}`, - [ - isWrapped - ? "SyntaxError: mismatched input '[' expecting " - : "SyntaxError: mismatched input 'METADATA' expecting ", - ], - addBracketsWarning() - ); + const collectFixturesSetup: Setup = async (...args) => { + const api = await setup(...args); + type ExpectErrors = Awaited>['expectErrors']; + return { + ...api, + expectErrors: async (...params: Parameters) => { + const [query, error = [], warning = []] = params; + const allStrings = + error.every((e) => typeof e === 'string') && + warning.every((w) => typeof w === 'string'); + if (allStrings) { + testCases.push({ + query, + error, + warning, + }); + } + }, + }; + }; - testErrorsAndWarnings( - `from remote-ccs:indexes ${setWrapping('METADATA _id')}`, - [], - addBracketsWarning() - ); - testErrorsAndWarnings( - `from *:indexes ${setWrapping('METADATA _id')}`, - [], - addBracketsWarning() - ); - } - testErrorsAndWarnings(`from index (metadata _id)`, [ - "SyntaxError: mismatched input '(metadata' expecting ", - ]); - testErrorsAndWarnings(`from ind*, other*`, []); - testErrorsAndWarnings(`from index*`, []); - testErrorsAndWarnings(`from *a_i*dex*`, []); - testErrorsAndWarnings(`from in*ex*`, []); - testErrorsAndWarnings(`from *n*ex`, []); - testErrorsAndWarnings(`from *n*ex*`, []); - testErrorsAndWarnings(`from i*d*x*`, []); - testErrorsAndWarnings(`from i*d*x`, []); - testErrorsAndWarnings(`from i***x*`, []); - testErrorsAndWarnings(`from i****`, []); - testErrorsAndWarnings(`from i**`, []); - testErrorsAndWarnings(`from index**`, []); - testErrorsAndWarnings(`from *ex`, []); - testErrorsAndWarnings(`from *ex*`, []); - testErrorsAndWarnings(`from in*ex`, []); - testErrorsAndWarnings(`from ind*ex`, []); - testErrorsAndWarnings(`from *,-.*`, []); - testErrorsAndWarnings(`from indexes*`, ['Unknown index [indexes*]']); - - testErrorsAndWarnings(`from remote-*:indexes*`, []); - testErrorsAndWarnings(`from remote-*:indexes`, []); - testErrorsAndWarnings(`from remote-ccs:indexes`, []); - testErrorsAndWarnings(`from a_index, remote-ccs:indexes`, []); - testErrorsAndWarnings('from .secret_index', []); - testErrorsAndWarnings('from my-index', []); - testErrorsAndWarnings('from numberField', ['Unknown index [numberField]']); - testErrorsAndWarnings('from policy', ['Unknown index [policy]']); - }); + runFromTestSuite(collectFixturesSetup); describe('row', () => { testErrorsAndWarnings('row', [ @@ -1370,230 +1283,6 @@ describe('validation logic', () => { }); }); - describe('stats', () => { - testErrorsAndWarnings('from a_index | stats ', [ - 'At least one aggregation or grouping expression required in [STATS]', - ]); - testErrorsAndWarnings('from a_index | stats by stringField', []); - testErrorsAndWarnings('from a_index | stats by ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - ]); - testErrorsAndWarnings('from a_index | stats numberField ', [ - 'Expected an aggregate function or group but got [numberField] of type [FieldAttribute]', - ]); - testErrorsAndWarnings('from a_index | stats numberField=', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - ]); - testErrorsAndWarnings('from a_index | stats numberField=5 by ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - ]); - testErrorsAndWarnings('from a_index | stats avg(numberField) by wrongField', [ - 'Unknown column [wrongField]', - ]); - testErrorsAndWarnings('from a_index | stats avg(numberField) by wrongField + 1', [ - 'Unknown column [wrongField]', - ]); - testErrorsAndWarnings('from a_index | stats avg(numberField) by var0 = wrongField + 1', [ - 'Unknown column [wrongField]', - ]); - testErrorsAndWarnings('from a_index | stats avg(numberField) by 1', []); - testErrorsAndWarnings('from a_index | stats avg(numberField) by percentile(numberField)', [ - 'STATS BY does not support function percentile', - ]); - testErrorsAndWarnings('from a_index | stats count(`numberField`)', []); - - // this is a scenario that was failing because "or" didn't accept "null" - testErrorsAndWarnings('from a_index | stats count(stringField == "a" or null)', []); - - for (const subCommand of ['keep', 'drop', 'eval']) { - testErrorsAndWarnings( - `from a_index | stats count(\`numberField\`) | ${subCommand} \`count(\`\`numberField\`\`)\` `, - [] - ); - } - - testErrorsAndWarnings( - 'from a_index | stats avg(numberField) by stringField, percentile(numberField) by ipField', - [ - "SyntaxError: mismatched input 'by' expecting ", - 'STATS BY does not support function percentile', - ] - ); - - testErrorsAndWarnings( - 'from a_index | stats avg(numberField), percentile(numberField, 50) by ipField', - [] - ); - - testErrorsAndWarnings( - 'from a_index | stats avg(numberField), percentile(numberField, 50) BY ipField', - [] - ); - for (const op of ['+', '-', '*', '/', '%']) { - testErrorsAndWarnings( - `from a_index | stats avg(numberField) ${op} percentile(numberField, 50) BY ipField`, - [] - ); - } - testErrorsAndWarnings('from a_index | stats count(* + 1) BY ipField', [ - "SyntaxError: no viable alternative at input 'count(* +'", - ]); - testErrorsAndWarnings('from a_index | stats count(* + round(numberField)) BY ipField', [ - "SyntaxError: no viable alternative at input 'count(* +'", - ]); - testErrorsAndWarnings('from a_index | stats count(round(*)) BY ipField', [ - 'Using wildcards (*) in round is not allowed', - ]); - testErrorsAndWarnings('from a_index | stats count(count(*)) BY ipField', [ - `Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [count(*)] of type [number]`, - ]); - testErrorsAndWarnings('from a_index | stats numberField + 1', [ - 'At least one aggregation function required in [STATS], found [numberField+1]', - ]); - - for (const nesting of NESTED_DEPTHS) { - const moreBuiltinWrapping = Array(nesting).fill('+1').join(''); - testErrorsAndWarnings( - `from a_index | stats 5 + avg(numberField) ${moreBuiltinWrapping}`, - [] - ); - testErrorsAndWarnings( - `from a_index | stats 5 ${moreBuiltinWrapping} + avg(numberField)`, - [] - ); - testErrorsAndWarnings(`from a_index | stats 5 ${moreBuiltinWrapping} + numberField`, [ - `At least one aggregation function required in [STATS], found [5${moreBuiltinWrapping}+numberField]`, - ]); - testErrorsAndWarnings(`from a_index | stats 5 + numberField ${moreBuiltinWrapping}`, [ - `At least one aggregation function required in [STATS], found [5+numberField${moreBuiltinWrapping}]`, - ]); - testErrorsAndWarnings( - `from a_index | stats 5 + numberField ${moreBuiltinWrapping}, var0 = sum(numberField)`, - [ - `At least one aggregation function required in [STATS], found [5+numberField${moreBuiltinWrapping}]`, - ] - ); - const evalFnWrapping = Array(nesting).fill('round(').join(''); - const closingWrapping = Array(nesting).fill(')').join(''); - // stress test the validation of the nesting check here - testErrorsAndWarnings( - `from a_index | stats ${evalFnWrapping} sum(numberField) ${closingWrapping}`, - [] - ); - testErrorsAndWarnings( - `from a_index | stats ${evalFnWrapping} sum(numberField) ${closingWrapping} + ${evalFnWrapping} sum(numberField) ${closingWrapping}`, - [] - ); - testErrorsAndWarnings( - `from a_index | stats ${evalFnWrapping} numberField + sum(numberField) ${closingWrapping}`, - [ - `Cannot combine aggregation and non-aggregation values in [STATS], found [${evalFnWrapping}numberField+sum(numberField)${closingWrapping}]`, - ] - ); - testErrorsAndWarnings( - `from a_index | stats ${evalFnWrapping} numberField + sum(numberField) ${closingWrapping}, var0 = sum(numberField)`, - [ - `Cannot combine aggregation and non-aggregation values in [STATS], found [${evalFnWrapping}numberField+sum(numberField)${closingWrapping}]`, - ] - ); - testErrorsAndWarnings( - `from a_index | stats var0 = ${evalFnWrapping} numberField + sum(numberField) ${closingWrapping}, var1 = sum(numberField)`, - [ - `Cannot combine aggregation and non-aggregation values in [STATS], found [${evalFnWrapping}numberField+sum(numberField)${closingWrapping}]`, - ] - ); - testErrorsAndWarnings( - `from a_index | stats ${evalFnWrapping} sum(numberField + numberField) ${closingWrapping}`, - [] - ); - testErrorsAndWarnings( - `from a_index | stats ${evalFnWrapping} sum(numberField + round(numberField)) ${closingWrapping}`, - [] - ); - testErrorsAndWarnings( - `from a_index | stats ${evalFnWrapping} sum(numberField + round(numberField)) ${closingWrapping} + ${evalFnWrapping} sum(numberField + round(numberField)) ${closingWrapping}`, - [] - ); - testErrorsAndWarnings( - `from a_index | stats sum(${evalFnWrapping} numberField ${closingWrapping} )`, - [] - ); - testErrorsAndWarnings( - `from a_index | stats sum(${evalFnWrapping} numberField ${closingWrapping} ) + sum(${evalFnWrapping} numberField ${closingWrapping} )`, - [] - ); - } - - testErrorsAndWarnings('from a_index | stats 5 + numberField + 1', [ - 'At least one aggregation function required in [STATS], found [5+numberField+1]', - ]); - - testErrorsAndWarnings('from a_index | stats numberField + 1 by ipField', [ - 'At least one aggregation function required in [STATS], found [numberField+1]', - ]); - - testErrorsAndWarnings( - 'from a_index | stats avg(numberField), percentile(numberField, 50) + 1 by ipField', - [] - ); - - testErrorsAndWarnings('from a_index | stats count(*)', []); - testErrorsAndWarnings('from a_index | stats count()', []); - testErrorsAndWarnings('from a_index | stats var0 = count(*)', []); - testErrorsAndWarnings('from a_index | stats var0 = count()', []); - testErrorsAndWarnings('from a_index | stats var0 = avg(numberField), count(*)', []); - testErrorsAndWarnings('from a_index | stats var0 = avg(fn(number)), count(*)', [ - 'Unknown function [fn]', - ]); - - // test all not allowed combinations - testErrorsAndWarnings('from a_index | STATS sum( numberField ) + abs( numberField ) ', [ - 'Cannot combine aggregation and non-aggregation values in [STATS], found [sum(numberField)+abs(numberField)]', - ]); - testErrorsAndWarnings('from a_index | STATS abs( numberField + sum( numberField )) ', [ - 'Cannot combine aggregation and non-aggregation values in [STATS], found [abs(numberField+sum(numberField))]', - ]); - - testErrorsAndWarnings( - `FROM index - | EVAL numberField * 3.281 - | STATS avg_numberField = AVG(\`numberField * 3.281\`)`, - [] - ); - - testErrorsAndWarnings( - `FROM index | STATS AVG(numberField) by round(numberField) + 1 | EVAL \`round(numberField) + 1\` / 2`, - [] - ); - - testErrorsAndWarnings(`from a_index | stats sum(case(false, 0, 1))`, []); - testErrorsAndWarnings(`from a_index | stats var0 = sum( case(false, 0, 1))`, []); - - describe('constant-only parameters', () => { - testErrorsAndWarnings('from index | stats by bucket(dateField, abs(numberField), "", "")', [ - 'Argument of [bucket] must be a constant, received [abs(numberField)]', - ]); - testErrorsAndWarnings( - 'from index | stats by bucket(dateField, abs(length(numberField)), "", "")', - ['Argument of [bucket] must be a constant, received [abs(length(numberField))]'] - ); - testErrorsAndWarnings('from index | stats by bucket(dateField, pi(), "", "")', []); - testErrorsAndWarnings('from index | stats by bucket(dateField, 1 + 30 / 10, "", "")', []); - testErrorsAndWarnings( - 'from index | stats by bucket(dateField, 1 + 30 / 10, concat("", ""), "")', - [] - ); - testErrorsAndWarnings( - 'from index | stats by bucket(dateField, numberField, stringField, stringField)', - [ - 'Argument of [bucket] must be a constant, received [numberField]', - 'Argument of [bucket] must be a constant, received [stringField]', - 'Argument of [bucket] must be a constant, received [stringField]', - ] - ); - }); - }); - describe('sort', () => { testErrorsAndWarnings('from a_index | sort ', [ "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts index a0c2d385c3e990..fcd17d54518253 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -7,18 +7,20 @@ */ import uniqBy from 'lodash/uniqBy'; -import type { +import { AstProviderFn, ESQLAstItem, + ESQLAstMetricsCommand, ESQLColumn, ESQLCommand, ESQLCommandMode, ESQLCommandOption, ESQLFunction, ESQLMessage, - ESQLSingleAstItem, ESQLSource, + walk, } from '@kbn/esql-ast'; +import type { ESQLAstField } from '@kbn/esql-ast/src/types'; import { CommandModeDefinition, CommandOptionsDefinition, @@ -50,11 +52,12 @@ import { isAssignment, isVariable, isValidLiteralOption, + isAggFunction, getQuotedColumnName, isInlineCastItem, } from '../shared/helpers'; import { collectVariables } from '../shared/variables'; -import { getMessageFromId } from './errors'; +import { getMessageFromId, errors } from './errors'; import type { ErrorTypes, ESQLRealField, @@ -351,15 +354,7 @@ function validateFunction( if (!isFnSupported.supported) { if (isFnSupported.reason === 'unknownFunction') { - messages.push( - getMessageFromId({ - messageId: 'unknownFunction', - values: { - name: astFunction.name, - }, - locations: astFunction.location, - }) - ); + messages.push(errors.unknownFunction(astFunction)); } // for nested functions skip this check and make the nested check fail later on if (isFnSupported.reason === 'unsupportedFunction' && !isNested) { @@ -467,9 +462,11 @@ function validateFunction( * and each should be validated as if each were constantOnly. */ allMatchingArgDefinitionsAreConstantOnly || forceConstantOnly, - // use the nesting flag for now just for stats + // use the nesting flag for now just for stats and metrics // TODO: revisit this part later on to make it more generic - parentCommand === 'stats' ? isNested || !isAssignment(astFunction) : false + parentCommand === 'stats' || parentCommand === 'metrics' + ? isNested || !isAssignment(astFunction) + : false ); if (messagesFromArg.some(({ code }) => code === 'expectedConstant')) { @@ -616,6 +613,153 @@ function validateSetting( return messages; } +/** + * Validate that a function is an aggregate function or that all children + * recursively terminate at either a literal or an aggregate function. + */ +const isFunctionAggClosed = (fn: ESQLFunction): boolean => + isAggFunction(fn) || areFunctionArgsAggClosed(fn); + +const areFunctionArgsAggClosed = (fn: ESQLFunction): boolean => + fn.args.every((arg) => isLiteralItem(arg) || (isFunctionItem(arg) && isFunctionAggClosed(arg))); + +/** + * Looks for first nested aggregate function in an aggregate function, recursively. + */ +const findNestedAggFunctionInAggFunction = (agg: ESQLFunction): ESQLFunction | undefined => { + for (const arg of agg.args) { + if (isFunctionItem(arg)) { + return isAggFunction(arg) ? arg : findNestedAggFunctionInAggFunction(arg); + } + } +}; + +/** + * Looks for first nested aggregate function in another aggregate a function, + * recursively. + * + * @param fn Function to check for nested aggregate functions. + * @param parentIsAgg Whether the parent function of `fn` is an aggregate function. + * @returns The first nested aggregate function in `fn`, or `undefined` if none is found. + */ +const findNestedAggFunction = ( + fn: ESQLFunction, + parentIsAgg: boolean = false +): ESQLFunction | undefined => { + if (isAggFunction(fn)) { + return parentIsAgg ? fn : findNestedAggFunctionInAggFunction(fn); + } + + for (const arg of fn.args) { + if (isFunctionItem(arg)) { + const nestedAgg = findNestedAggFunction(arg, parentIsAgg || isAggFunction(fn)); + if (nestedAgg) return nestedAgg; + } + } +}; + +/** + * Validates aggregates fields: `... ...`. + */ +const validateAggregates = ( + command: ESQLCommand, + aggregates: ESQLAstField[], + references: ReferenceMaps +) => { + const messages: ESQLMessage[] = []; + + // Should never happen. + if (!aggregates.length) { + messages.push(errors.unexpected(command.location)); + return messages; + } + + let hasMissingAggregationFunctionError = false; + + for (const aggregate of aggregates) { + if (isFunctionItem(aggregate)) { + messages.push(...validateFunction(aggregate, command.name, undefined, references)); + + let hasAggregationFunction = false; + + walk(aggregate, { + visitFunction: (fn) => { + const definition = getFunctionDefinition(fn.name); + if (!definition) return; + if (definition.type === 'agg') hasAggregationFunction = true; + }, + }); + + if (!hasAggregationFunction) { + hasMissingAggregationFunctionError = true; + messages.push(errors.noAggFunction(command, aggregate)); + } + } else if (isColumnItem(aggregate)) { + messages.push(errors.unknownAggFunction(aggregate)); + } else { + // Should never happen. + } + } + + if (hasMissingAggregationFunctionError) { + return messages; + } + + for (const aggregate of aggregates) { + if (isFunctionItem(aggregate)) { + const fn = isAssignment(aggregate) ? aggregate.args[1] : aggregate; + if (isFunctionItem(fn) && !isFunctionAggClosed(fn)) { + messages.push(errors.expressionNotAggClosed(command, fn)); + } + } + } + + if (messages.length) { + return messages; + } + + for (const aggregate of aggregates) { + if (isFunctionItem(aggregate)) { + const aggInAggFunction = findNestedAggFunction(aggregate); + if (aggInAggFunction) { + messages.push(errors.aggInAggFunction(aggInAggFunction)); + break; + } + } + } + + return messages; +}; + +/** + * Validates grouping fields of the BY clause: `... BY `. + */ +const validateByGrouping = ( + fields: ESQLAstItem[], + commandName: string, + referenceMaps: ReferenceMaps, + multipleParams: boolean +): ESQLMessage[] => { + const messages: ESQLMessage[] = []; + for (const field of fields) { + if (!Array.isArray(field)) { + if (!multipleParams) { + if (isColumnItem(field)) { + messages.push(...validateColumnForCommand(field, commandName, referenceMaps)); + } + } else { + if (isColumnItem(field)) { + messages.push(...validateColumnForCommand(field, commandName, referenceMaps)); + } + if (isFunctionItem(field)) { + messages.push(...validateFunction(field, commandName, 'by', referenceMaps)); + } + } + } + } + return messages; +}; + function validateOption( option: ESQLCommandOption, optionDef: CommandOptionsDefinition | undefined, @@ -673,38 +817,40 @@ function validateSource( if (source.incomplete) { return messages; } - const commandDef = getCommandDefinition(commandName); - // give up on validate if CCS for now + const hasCCS = hasCCSSource(source.name); - if (!hasCCS) { - const isWildcardAndNotSupported = - hasWildcard(source.name) && !commandDef.signature.params.some(({ wildcards }) => wildcards); - if (isWildcardAndNotSupported) { + if (hasCCS) { + return messages; + } + + const commandDef = getCommandDefinition(commandName); + const isWildcardAndNotSupported = + hasWildcard(source.name) && !commandDef.signature.params.some(({ wildcards }) => wildcards); + if (isWildcardAndNotSupported) { + messages.push( + getMessageFromId({ + messageId: 'wildcardNotSupportedForCommand', + values: { command: commandName.toUpperCase(), value: source.name }, + locations: source.location, + }) + ); + } else { + if (source.sourceType === 'index' && !sourceExists(source.name, sources)) { messages.push( getMessageFromId({ - messageId: 'wildcardNotSupportedForCommand', - values: { command: commandName.toUpperCase(), value: source.name }, + messageId: 'unknownIndex', + values: { name: source.name }, + locations: source.location, + }) + ); + } else if (source.sourceType === 'policy' && !policies.has(source.name)) { + messages.push( + getMessageFromId({ + messageId: 'unknownPolicy', + values: { name: source.name }, locations: source.location, }) ); - } else { - if (source.sourceType === 'index' && !sourceExists(source.name, sources)) { - messages.push( - getMessageFromId({ - messageId: 'unknownIndex', - values: { name: source.name }, - locations: source.location, - }) - ); - } else if (source.sourceType === 'policy' && !policies.has(source.name)) { - messages.push( - getMessageFromId({ - messageId: 'unknownPolicy', - values: { name: source.name }, - locations: source.location, - }) - ); - } } } @@ -720,15 +866,7 @@ function validateColumnForCommand( if (commandName === 'row') { if (!references.variables.has(column.name)) { - messages.push( - getMessageFromId({ - messageId: 'unknownColumn', - values: { - name: column.name, - }, - locations: column.location, - }) - ); + messages.push(errors.unknownColumn(column)); } } else { const columnName = getQuotedColumnName(column); @@ -780,21 +918,55 @@ function validateColumnForCommand( } } else { if (column.name) { - messages.push( - getMessageFromId({ - messageId: 'unknownColumn', - values: { - name: column.name, - }, - locations: column.location, - }) - ); + messages.push(errors.unknownColumn(column)); } } } return messages; } +export function validateSources( + command: ESQLCommand, + sources: ESQLSource[], + references: ReferenceMaps +): ESQLMessage[] { + const messages: ESQLMessage[] = []; + + for (const source of sources) { + messages.push(...validateSource(source, command.name, references)); + } + + return messages; +} + +/** + * Validates the METRICS source command: + * + * METRICS [ [ BY ]] + */ +const validateMetricsCommand = ( + command: ESQLAstMetricsCommand, + references: ReferenceMaps +): ESQLMessage[] => { + const messages: ESQLMessage[] = []; + const { sources, aggregates, grouping } = command; + + // METRICS ... + messages.push(...validateSources(command, sources, references)); + + // ... ... + if (aggregates && aggregates.length) { + messages.push(...validateAggregates(command, aggregates, references)); + + // ... BY + if (grouping && grouping.length) { + messages.push(...validateByGrouping(grouping, 'metrics', references, true)); + } + } + + return messages; +}; + function validateCommand(command: ESQLCommand, references: ReferenceMaps): ESQLMessage[] { const messages: ESQLMessage[] = []; if (command.incomplete) { @@ -807,62 +979,63 @@ function validateCommand(command: ESQLCommand, references: ReferenceMaps): ESQLM messages.push(...commandDef.validate(command)); } - // Now validate arguments - for (const commandArg of command.args) { - const wrappedArg = Array.isArray(commandArg) ? commandArg : [commandArg]; - for (const arg of wrappedArg) { - if (isFunctionItem(arg)) { - messages.push(...validateFunction(arg, command.name, undefined, references)); - } + switch (commandDef.name) { + case 'metrics': { + const metrics = command as ESQLAstMetricsCommand; + messages.push(...validateMetricsCommand(metrics, references)); + break; + } + default: { + // Now validate arguments + for (const commandArg of command.args) { + const wrappedArg = Array.isArray(commandArg) ? commandArg : [commandArg]; + for (const arg of wrappedArg) { + if (isFunctionItem(arg)) { + messages.push(...validateFunction(arg, command.name, undefined, references)); + } - if (isSettingItem(arg)) { - messages.push(...validateSetting(arg, commandDef.modes[0], command, references)); - } + if (isSettingItem(arg)) { + messages.push(...validateSetting(arg, commandDef.modes[0], command, references)); + } - if (isOptionItem(arg)) { - messages.push( - ...validateOption( - arg, - commandDef.options.find(({ name }) => name === arg.name), - command, - references - ) - ); - } - if (isColumnItem(arg)) { - if (command.name === 'stats') { - messages.push( - getMessageFromId({ - messageId: 'unknownAggregateFunction', - values: { - value: (arg as ESQLSingleAstItem).name, - type: 'FieldAttribute', - }, - locations: (arg as ESQLSingleAstItem).location, - }) - ); - } else { - messages.push(...validateColumnForCommand(arg, command.name, references)); + if (isOptionItem(arg)) { + messages.push( + ...validateOption( + arg, + commandDef.options.find(({ name }) => name === arg.name), + command, + references + ) + ); + } + if (isColumnItem(arg)) { + if (command.name === 'stats') { + messages.push(errors.unknownAggFunction(arg)); + } else { + messages.push(...validateColumnForCommand(arg, command.name, references)); + } + } + if (isTimeIntervalItem(arg)) { + messages.push( + getMessageFromId({ + messageId: 'unsupportedTypeForCommand', + values: { + command: command.name.toUpperCase(), + type: 'date_period', + value: arg.name, + }, + locations: arg.location, + }) + ); + } + if (isSourceItem(arg)) { + messages.push(...validateSource(arg, command.name, references)); + } } } - if (isTimeIntervalItem(arg)) { - messages.push( - getMessageFromId({ - messageId: 'unsupportedTypeForCommand', - values: { - command: command.name.toUpperCase(), - type: 'date_period', - value: arg.name, - }, - locations: arg.location, - }) - ); - } - if (isSourceItem(arg)) { - messages.push(...validateSource(arg, command.name, references)); - } } } + // no need to check for mandatory options passed // as they are already validated at syntax level return messages; @@ -940,7 +1113,6 @@ export async function validateQuery( if (!options.ignoreOnMissingCallbacks) { return result; } - const { errors, warnings } = result; const finalCallbacks = callbacks || {}; const errorTypoesToIgnore = Object.entries(ignoreErrorsMap).reduce((acc, [key, errorCodes]) => { if ( @@ -953,7 +1125,7 @@ export async function validateQuery( } return acc; }, {} as Partial>); - const filteredErrors = errors + const filteredErrors = result.errors .filter((error) => { if ('severity' in error) { return true; @@ -970,7 +1142,7 @@ export async function validateQuery( } : error ); - return { errors: filteredErrors, warnings }; + return { errors: filteredErrors, warnings: result.warnings }; } /** @@ -986,7 +1158,8 @@ async function validateAst( ): Promise { const messages: ESQLMessage[] = []; - const { ast, errors } = await astProvider(queryString); + const parsingResult = await astProvider(queryString); + const { ast } = parsingResult; const [sources, availableFields, availablePolicies] = await Promise.all([ // retrieve the list of available sources @@ -1023,18 +1196,19 @@ async function validateAst( messages.push(...validateUnsupportedTypeFields(availableFields)); for (const command of ast) { - const commandMessages = validateCommand(command, { + const references: ReferenceMaps = { sources, fields: availableFields, policies: availablePolicies, variables, query: queryString, - }); + }; + const commandMessages = validateCommand(command, references); messages.push(...commandMessages); } return { - errors: [...errors, ...messages.filter(({ type }) => type === 'error')], + errors: [...parsingResult.errors, ...messages.filter(({ type }) => type === 'error')], warnings: messages.filter(({ type }) => type === 'warning'), }; } diff --git a/test/api_integration/apis/esql/errors.ts b/test/api_integration/apis/esql/errors.ts index ec81e25e7d0f74..e74f86efcb44ca 100644 --- a/test/api_integration/apis/esql/errors.ts +++ b/test/api_integration/apis/esql/errors.ts @@ -152,6 +152,7 @@ export default function ({ getService }: FtrProviderContext) { ); for (const policy of policies) { log.info(`deleting policy "${policy}"...`); + // TODO: Maybe `policy` -> `policy.name`? await es.enrich.deletePolicy({ name: policy }, { ignore: [404] }); } } From 5259fa6764c82e8584c6df2d50703bf2e2f48d63 Mon Sep 17 00:00:00 2001 From: Alex Szabo Date: Thu, 20 Jun 2024 09:51:37 +0200 Subject: [PATCH 108/123] [CI] Use legacy vault for deployment credentials (#184944) ## Summary With the migration to the shared buildkite infra, we've also switched to using the ci-prod vault (https://vault-ci-prod.elastic.dev) for all CI-related secrets. We found it reasonable then, to also switch the storage of the credentials for the deployments there. It's since been proven unnecessary, even confusing for developers, as they might not be adequately set up for accessing the two vaults. We've also learned, that both of these vault instances are here to stay, so there's no push to migrate everything to the ci-prod instance. So, this PR switches back to using the legacy vault in all cases for storing deployment keys, as it fits better with the developers' daily secret handling duties. Also, adds a cleanup part to the purge routine. - [x] extract vault read / write to a parametric shell script, because the typescript invocations to vault won't have an easy access to the `set_in_legacy_vault` --- .../scripts/common/deployment_credentials.sh | 21 +++++++ .buildkite/scripts/common/vault_fns.sh | 58 ++++++++++++++++++- .../scripts/steps/cloud/build_and_deploy.sh | 9 +-- .../scripts/steps/cloud/purge_deployments.ts | 8 +-- .../scripts/steps/cloud/purge_projects.ts | 10 +++- .buildkite/scripts/steps/serverless/deploy.sh | 11 ++-- 6 files changed, 102 insertions(+), 15 deletions(-) create mode 100755 .buildkite/scripts/common/deployment_credentials.sh diff --git a/.buildkite/scripts/common/deployment_credentials.sh b/.buildkite/scripts/common/deployment_credentials.sh new file mode 100755 index 00000000000000..48f5be56a3bfb1 --- /dev/null +++ b/.buildkite/scripts/common/deployment_credentials.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/common/vault_fns.sh + +## Usage +# ./deployment_credentials.sh set ... +# ./deployment_credentials.sh unset +# ./deployment_credentials.sh print + +if [[ "${1:-}" == "set" ]]; then + set_in_legacy_vault "${@:2}" +elif [[ "${1:-}" == "unset" ]]; then + unset_in_legacy_vault "${@:2}" +elif [[ "${1:-}" == "print" ]]; then + print_legacy_vault_read "${2}" +else + echo "Unknown command: $1" + exit 1 +fi diff --git a/.buildkite/scripts/common/vault_fns.sh b/.buildkite/scripts/common/vault_fns.sh index 022a22541d6bf5..c9c51b2c7bb92c 100644 --- a/.buildkite/scripts/common/vault_fns.sh +++ b/.buildkite/scripts/common/vault_fns.sh @@ -1,7 +1,8 @@ #!/bin/bash -# TODO: remove after https://github.com/elastic/kibana-operations/issues/15 is done -if [[ "${VAULT_ADDR:-}" == *"secrets.elastic.co"* ]]; then +# TODO: rewrite after https://github.com/elastic/kibana-operations/issues/15 is done +export LEGACY_VAULT_ADDR="https://secrets.elastic.co:8200" +if [[ "${VAULT_ADDR:-}" == "$LEGACY_VAULT_ADDR" ]]; then VAULT_PATH_PREFIX="secret/kibana-issues/dev" VAULT_KV_PREFIX="secret/kibana-issues/dev" IS_LEGACY_VAULT_ADDR=true @@ -85,3 +86,56 @@ function get_vault_secret_id() { echo "$VAULT_SECRET_ID" } + +function set_in_legacy_vault() { + key_path=$1 + shift + fields=("$@") + + VAULT_ROLE_ID="$(get_vault_role_id)" + VAULT_SECRET_ID="$(get_vault_secret_id)" + VAULT_TOKEN_BAK="$VAULT_TOKEN" + + # Make sure to either keep this variable name `VAULT_TOKEN` or unset `VAULT_TOKEN`, + # otherwise the VM's default token will be used, that's connected to the ci-prod vault instance + VAULT_TOKEN=$(VAULT_ADDR=$LEGACY_VAULT_ADDR vault write -field=token auth/approle/login role_id="$VAULT_ROLE_ID" secret_id="$VAULT_SECRET_ID") + VAULT_ADDR=$LEGACY_VAULT_ADDR vault login -no-print "$VAULT_TOKEN" + + set +e + # shellcheck disable=SC2068 + vault write -address=$LEGACY_VAULT_ADDR "secret/kibana-issues/dev/cloud-deploy/$key_path" ${fields[@]} + EXIT_CODE=$? + set -e + + VAULT_TOKEN="$VAULT_TOKEN_BAK" + + return $EXIT_CODE +} + +function unset_in_legacy_vault() { + key_path=$1 + + VAULT_ROLE_ID="$(get_vault_role_id)" + VAULT_SECRET_ID="$(get_vault_secret_id)" + VAULT_TOKEN_BAK="$VAULT_TOKEN" + + # Make sure to either keep this variable name `VAULT_TOKEN` or unset `VAULT_TOKEN`, + # otherwise the VM's default token will be used, that's connected to the ci-prod vault instance + VAULT_TOKEN=$(VAULT_ADDR=$LEGACY_VAULT_ADDR vault write -field=token auth/approle/login role_id="$VAULT_ROLE_ID" secret_id="$VAULT_SECRET_ID") + VAULT_ADDR=$LEGACY_VAULT_ADDR vault login -no-print "$VAULT_TOKEN" + + set +e + vault delete -address=$LEGACY_VAULT_ADDR "secret/kibana-issues/dev/cloud-deploy/$key_path" + EXIT_CODE=$? + set -e + + VAULT_TOKEN="$VAULT_TOKEN_BAK" + + return $EXIT_CODE +} + +function print_legacy_vault_read() { + key_path=$1 + + echo "vault read -address=$LEGACY_VAULT_ADDR secret/kibana-issues/dev/cloud-deploy/$key_path" +} diff --git a/.buildkite/scripts/steps/cloud/build_and_deploy.sh b/.buildkite/scripts/steps/cloud/build_and_deploy.sh index 1287d0f0328c3d..10d18030c8811c 100755 --- a/.buildkite/scripts/steps/cloud/build_and_deploy.sh +++ b/.buildkite/scripts/steps/cloud/build_and_deploy.sh @@ -82,7 +82,9 @@ if [ -z "${CLOUD_DEPLOYMENT_ID}" ] || [ "${CLOUD_DEPLOYMENT_ID}" = 'null' ]; the echo "Writing to vault..." - vault_kv_set "cloud-deploy/$CLOUD_DEPLOYMENT_NAME" username="$CLOUD_DEPLOYMENT_USERNAME" password="$CLOUD_DEPLOYMENT_PASSWORD" + set_in_legacy_vault "$CLOUD_DEPLOYMENT_NAME" \ + username="$CLOUD_DEPLOYMENT_USERNAME" \ + password="$CLOUD_DEPLOYMENT_PASSWORD" echo "Enabling Stack Monitoring..." jq ' @@ -114,6 +116,7 @@ else ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/deploy.json > "$ECCTL_LOGS" fi +VAULT_READ_COMMAND=$(print_legacy_vault_read "$CLOUD_DEPLOYMENT_NAME") CLOUD_DEPLOYMENT_KIBANA_URL=$(ecctl deployment show "$CLOUD_DEPLOYMENT_ID" | jq -r '.resources.kibana[0].info.metadata.aliased_url') CLOUD_DEPLOYMENT_ELASTICSEARCH_URL=$(ecctl deployment show "$CLOUD_DEPLOYMENT_ID" | jq -r '.resources.elasticsearch[0].info.metadata.aliased_url') @@ -125,9 +128,7 @@ Kibana: $CLOUD_DEPLOYMENT_KIBANA_URL Elasticsearch: $CLOUD_DEPLOYMENT_ELASTICSEARCH_URL -Credentials: \`vault kv get $VAULT_KV_PREFIX/cloud-deploy/$CLOUD_DEPLOYMENT_NAME\` - -(Stored in the production vault: VAULT_ADDR=https://vault-ci-prod.elastic.dev, more info: https://docs.elastic.dev/ci/using-secrets) +Credentials: \`$VAULT_READ_COMMAND\` Kibana image: \`$KIBANA_CLOUD_IMAGE\` diff --git a/.buildkite/scripts/steps/cloud/purge_deployments.ts b/.buildkite/scripts/steps/cloud/purge_deployments.ts index d50e62569b86f8..67f39afc67b3c7 100644 --- a/.buildkite/scripts/steps/cloud/purge_deployments.ts +++ b/.buildkite/scripts/steps/cloud/purge_deployments.ts @@ -7,12 +7,10 @@ */ import { execSync } from 'child_process'; +import { getKibanaDir } from '#pipeline-utils'; const deploymentsListJson = execSync('ecctl deployment list --output json').toString(); const { deployments } = JSON.parse(deploymentsListJson); -const secretBasePath = process.env.VAULT_ADDR?.match(/secrets\.elastic\.co/g) - ? 'secret/kibana-issues/dev' - : 'secret/ci/elastic-kibana'; const prDeployments = deployments.filter((deployment: any) => deployment.name.startsWith('kibana-pr-') @@ -70,7 +68,9 @@ for (const deployment of deploymentsToPurge) { console.log(`Scheduling deployment for deletion: ${deployment.name} / ${deployment.id}`); try { execSync(`ecctl deployment shutdown --force '${deployment.id}'`, { stdio: 'inherit' }); - execSync(`vault delete ${secretBasePath}/cloud-deploy/${deployment.name}`, { + + execSync(`.buildkite/scripts/common/deployment_credentials.sh unset ${deployment.name}`, { + cwd: getKibanaDir(), stdio: 'inherit', }); } catch (ex) { diff --git a/.buildkite/scripts/steps/cloud/purge_projects.ts b/.buildkite/scripts/steps/cloud/purge_projects.ts index 84083417f62678..efd54eeeb0c70b 100644 --- a/.buildkite/scripts/steps/cloud/purge_projects.ts +++ b/.buildkite/scripts/steps/cloud/purge_projects.ts @@ -8,6 +8,7 @@ import { execSync } from 'child_process'; import axios from 'axios'; +import { getKibanaDir } from '#pipeline-utils'; async function getPrProjects() { const match = /^(keep.?)?kibana-pr-([0-9]+)-(elasticsearch|security|observability)$/; @@ -43,12 +44,19 @@ async function getPrProjects() { async function deleteProject({ type, id, + name, }: { type: 'elasticsearch' | 'observability' | 'security'; id: number; + name: string; }) { try { await projectRequest.delete(`/api/v1/serverless/projects/${type}/${id}`); + + execSync(`.buildkite/scripts/common/deployment_credentials.sh unset ${name}`, { + cwd: getKibanaDir(), + stdio: 'inherit', + }); } catch (e) { if (e.isAxiosError) { const message = @@ -61,7 +69,7 @@ async function deleteProject({ async function purgeProjects() { const prProjects = await getPrProjects(); - const projectsToPurge = []; + const projectsToPurge: typeof prProjects = []; for (const project of prProjects) { const NOW = new Date().getTime() / 1000; const DAY_IN_SECONDS = 60 * 60 * 24; diff --git a/.buildkite/scripts/steps/serverless/deploy.sh b/.buildkite/scripts/steps/serverless/deploy.sh index e67795fcbf65df..68c7d285c4c8dd 100644 --- a/.buildkite/scripts/steps/serverless/deploy.sh +++ b/.buildkite/scripts/steps/serverless/deploy.sh @@ -88,7 +88,10 @@ deploy() { echo "Write to vault..." - vault_kv_set "cloud-deploy/$VAULT_KEY_NAME" username="$PROJECT_USERNAME" password="$PROJECT_PASSWORD" id="$PROJECT_ID" + set_in_legacy_vault "$VAULT_KEY_NAME" \ + username="$PROJECT_USERNAME" \ + password="$PROJECT_PASSWORD" \ + id="$PROJECT_ID" else echo "Updating project..." @@ -109,6 +112,8 @@ deploy() { PROJECT_KIBANA_LOGIN_URL="${PROJECT_KIBANA_URL}/login" PROJECT_ELASTICSEARCH_URL=$(jq -r '.endpoints.elasticsearch' $PROJECT_INFO_LOGS) + VAULT_READ_COMMAND=$(print_legacy_vault_read "$VAULT_KEY_NAME") + cat << EOF | buildkite-agent annotate --style "info" --context "project-$PROJECT_TYPE" ### $PROJECT_TYPE_LABEL Deployment @@ -116,9 +121,7 @@ Kibana: $PROJECT_KIBANA_LOGIN_URL Elasticsearch: $PROJECT_ELASTICSEARCH_URL -Credentials: \`vault kv get $VAULT_KV_PREFIX/cloud-deploy/$VAULT_KEY_NAME\` - -(Stored in the production vault: VAULT_ADDR=https://vault-ci-prod.elastic.dev, more info: https://docs.elastic.dev/ci/using-secrets) +Credentials: \`$VAULT_READ_COMMAND\` Kibana image: \`$KIBANA_IMAGE\` EOF From f05416e2250801db138083583cf8aa9406dd8a26 Mon Sep 17 00:00:00 2001 From: Tre Date: Thu, 20 Jun 2024 09:18:22 +0100 Subject: [PATCH 109/123] [FTR](search_oss) update common serverless api tests to use api keys (#185030) ## Summary - update api tests in `x-pack/test_serverless/api_integration/test_suites/common/search_oss/` Contributes to: https://github.com/elastic/kibana/issues/180834 --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../test_suites/common/search_oss/bsearch.ts | 30 ++++++++++---- .../test_suites/common/search_oss/search.ts | 39 ++++++++++++++----- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts index ba1f974a01608d..063f6623738bbb 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/bsearch.ts @@ -10,6 +10,7 @@ import request from 'superagent'; import { inflateResponse } from '@kbn/bfetch-plugin/public/streaming'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; +import { RoleCredentials } from '../../../../shared/services'; import type { FtrProviderContext } from '../../../ftr_provider_context'; import { painlessErrReq } from './painless_err_req'; import { verifyErrorResponse } from './verify_error'; @@ -24,18 +25,28 @@ function parseBfetchResponse(resp: request.Response, compressed: boolean = false } export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + let roleAuthc: RoleCredentials; + describe('bsearch', () => { + before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + }); + after(async () => { + await svlUserManager.invalidateApiKeyForRole(roleAuthc); + }); describe('post', () => { it('should return 200 a single response', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/bsearch`) .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ batch: [ { @@ -66,11 +77,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return 200 a single response from compressed', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/bsearch?compress=true`) .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ batch: [ { @@ -101,11 +113,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return a batch of successful responses', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/bsearch`) .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ batch: [ { @@ -146,11 +159,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return error for not found strategy', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/bsearch`) .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ batch: [ { @@ -179,11 +193,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return 400 when index type is provided in "es" strategy', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/bsearch`) .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ batch: [ { @@ -221,11 +236,12 @@ export default function ({ getService }: FtrProviderContext) { await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); }); it('should return 400 "search_phase_execution_exception" for Painless error in "es" strategy', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/bsearch`) .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ batch: [ { diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/search.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/search.ts index 85a57a2c2d272a..51702ad4e272a6 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/search_oss/search.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/search_oss/search.ts @@ -7,17 +7,27 @@ import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import expect from '@kbn/expect'; +import { RoleCredentials } from '../../../../shared/services'; import type { FtrProviderContext } from '../../../ftr_provider_context'; import { painlessErrReq } from './painless_err_req'; import { verifyErrorResponse } from './verify_error'; export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const svlCommonApi = getService('svlCommonApi'); const kibanaServer = getService('kibanaServer'); + const svlUserManager = getService('svlUserManager'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + let roleAuthc: RoleCredentials; + describe('search', () => { + before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + }); + after(async () => { + await svlUserManager.invalidateApiKeyForRole(roleAuthc); + }); before(async () => { // TODO: emptyKibanaIndex fails in Serverless with // "index_not_found_exception: no such index [.kibana_ingest]", @@ -31,11 +41,12 @@ export default function ({ getService }: FtrProviderContext) { }); describe('post', () => { it('should return 200 when correctly formatted searches are provided', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/search/es`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ params: { body: { @@ -55,11 +66,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return 200 if terminated early', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/search/es`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ params: { terminateAfter: 1, @@ -82,11 +94,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return 404 when if no strategy is provided', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/search`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ body: { query: { @@ -100,11 +113,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return 404 when if unknown strategy is provided', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/search/banana`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ body: { query: { @@ -120,11 +134,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return 400 with illegal ES argument', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/search/es`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ params: { timeout: 1, // This should be a time range string! @@ -143,11 +158,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return 400 with a bad body', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/search/es`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send({ params: { body: { @@ -162,11 +178,12 @@ export default function ({ getService }: FtrProviderContext) { }); it('should return 400 for a painless error', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .post(`/internal/search/es`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send(painlessErrReq) .expect(400); @@ -176,22 +193,24 @@ export default function ({ getService }: FtrProviderContext) { describe('delete', () => { it('should return 404 when no search id provided', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .delete(`/internal/search/es`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send() .expect(404); verifyErrorResponse(resp.body, 404); }); it('should return 400 when trying a delete on a non supporting strategy', async () => { - const resp = await supertest + const resp = await supertestWithoutAuth .delete(`/internal/search/es/123`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') // TODO: API requests in Serverless require internal request headers .set(svlCommonApi.getInternalRequestHeader()) + .set(roleAuthc.apiKeyHeader) .send() .expect(400); verifyErrorResponse(resp.body, 400); From c97e098e294f1eca7885c5be6d4adc390841c346 Mon Sep 17 00:00:00 2001 From: Tiago Vila Verde Date: Thu, 20 Jun 2024 11:30:08 +0200 Subject: [PATCH 110/123] [Entity Analytics] Add criticality column to All Users table In Explore pages (#186456) This PR, a follow-up to #186375, adds a new column for Asset Criticality to the "All hosts" tab in the Explore/Hosts page. If any of the hosts has criticality data assigned, it will be displayed in the new column. If no criticality has been assigned, the field is left blank. Screenshot 2024-06-19 at 13 46 52 ### How to test 1. Make sure you have test data with Asset Criticality. - Either use the [datagen tool](https://github.com/elastic/security-documents-generator) or just make sure to assign criticality to already existing hosts 2. Enable Asset Criticality settings in `Stack Management > Kibana > Advanced Settings` 3. Navigate to `Explore > Users > All Users` Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../security_solution/hosts/common/index.ts | 1 + .../security_solution/users/all/index.ts | 1 + .../users/components/all_users/index.tsx | 36 ++++++++-- .../components/all_users/translations.ts | 7 ++ .../factory/users/all/index.ts | 72 +++++++++++++------ 5 files changed, 90 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/common/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/common/index.ts index b434ee20cfb034..15dda8058221d8 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/common/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/common/index.ts @@ -37,6 +37,7 @@ export interface HostItem { host?: Maybe; lastSeen?: Maybe; risk?: string; + criticality?: string; } export interface HostValue { diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/users/all/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/users/all/index.ts index 19406bbca35d9e..1d8feedf95e74b 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/users/all/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/users/all/index.ts @@ -14,6 +14,7 @@ export interface User { lastSeen: string; domain: string; risk?: RiskSeverity; + criticality?: string; } export interface UsersStrategyResponse extends IEsSearchResponse { diff --git a/x-pack/plugins/security_solution/public/explore/users/components/all_users/index.tsx b/x-pack/plugins/security_solution/public/explore/users/components/all_users/index.tsx index 6948009ebb188b..d05c9551a25181 100644 --- a/x-pack/plugins/security_solution/public/explore/users/components/all_users/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/components/all_users/index.tsx @@ -9,6 +9,9 @@ import React, { useCallback, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import { EuiLink, EuiText } from '@elastic/eui'; +import { ENABLE_ASSET_CRITICALITY_SETTING } from '../../../../../common/constants'; +import { AssetCriticalityBadge } from '../../../../entity_analytics/components/asset_criticality'; +import type { CriticalityLevelWithUnassigned } from '../../../../../common/entity_analytics/asset_criticality/types'; import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date'; import { UserDetailsLink } from '../../../../common/components/links'; import { @@ -32,7 +35,7 @@ import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml import { VIEW_USERS_BY_SEVERITY } from '../../../../entity_analytics/components/user_risk_score_table/translations'; import { SecurityPageName } from '../../../../app/types'; import { UsersTableType } from '../../store/model'; -import { useNavigateTo } from '../../../../common/lib/kibana'; +import { useNavigateTo, useUiSetting$ } from '../../../../common/lib/kibana'; const tableType = usersModel.UsersTableType.allUsers; @@ -53,7 +56,8 @@ export type UsersTableColumns = [ Columns, Columns, Columns, - Columns? + Columns?, + Columns? ]; const rowItems: ItemsPerRow[] = [ @@ -69,7 +73,8 @@ const rowItems: ItemsPerRow[] = [ const getUsersColumns = ( showRiskColumn: boolean, - dispatchSeverityUpdate: (s: RiskSeverity) => void + dispatchSeverityUpdate: (s: RiskSeverity) => void, + isAssetCriticalityEnabled: boolean ): UsersTableColumns => { const columns: UsersTableColumns = [ { @@ -138,6 +143,25 @@ const getUsersColumns = ( }); } + if (isAssetCriticalityEnabled) { + columns.push({ + field: 'criticality', + name: i18n.ASSET_CRITICALITY, + truncateText: false, + mobileOptions: { show: true }, + sortable: false, + render: (assetCriticality: CriticalityLevelWithUnassigned) => { + if (!assetCriticality) return getEmptyTagValue(); + return ( + + ); + }, + }); + } + return columns; }; @@ -217,9 +241,11 @@ const UsersTableComponent: React.FC = ({ [dispatch, navigateTo] ); + const [isAssetCriticalityEnabled] = useUiSetting$(ENABLE_ASSET_CRITICALITY_SETTING); const columns = useMemo( - () => getUsersColumns(isPlatinumOrTrialLicense, dispatchSeverityUpdate), - [isPlatinumOrTrialLicense, dispatchSeverityUpdate] + () => + getUsersColumns(isPlatinumOrTrialLicense, dispatchSeverityUpdate, isAssetCriticalityEnabled), + [isPlatinumOrTrialLicense, dispatchSeverityUpdate, isAssetCriticalityEnabled] ); return ( diff --git a/x-pack/plugins/security_solution/public/explore/users/components/all_users/translations.ts b/x-pack/plugins/security_solution/public/explore/users/components/all_users/translations.ts index e1e3f43c6af32d..0a96f6ff717b82 100644 --- a/x-pack/plugins/security_solution/public/explore/users/components/all_users/translations.ts +++ b/x-pack/plugins/security_solution/public/explore/users/components/all_users/translations.ts @@ -42,3 +42,10 @@ export const UNIT = (totalCount: number) => export const USER_RISK = i18n.translate('xpack.securitySolution.usersTable.riskTitle', { defaultMessage: 'User risk level', }); + +export const ASSET_CRITICALITY = i18n.translate( + 'xpack.securitySolution.hostsTable.assetCriticality', + { + defaultMessage: 'Asset criticality', + } +); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts index 18d20b5080352f..7ae8371152ddeb 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/all/index.ts @@ -9,6 +9,8 @@ import { getOr } from 'lodash/fp'; import type { IEsSearchResponse } from '@kbn/search-types'; import type { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; +import type { AggregationsAggregate, SearchResponse } from '@elastic/elasticsearch/lib/api/types'; +import _ from 'lodash'; import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants'; import { inspectStringifyObject } from '../../../../../utils/build_query'; @@ -28,6 +30,9 @@ import { RiskScoreEntity, RiskQueries, } from '../../../../../../common/search_strategy'; +import { buildAssetCriticalityQuery } from '../../asset_criticality/query.asset_criticality.dsl'; +import { getAssetCriticalityIndex } from '../../../../../../common/entity_analytics/asset_criticality'; +import type { AssetCriticalityRecord } from '../../../../../../common/api/entity_analytics'; export const allUsers: SecuritySolutionFactory = { buildDsl: (options) => { @@ -103,29 +108,22 @@ async function enhanceEdges( esClient: IScopedClusterClient, isNewRiskScoreModuleInstalled: boolean ): Promise { - const userRiskData = await getUserRiskData( - esClient, - spaceId, - userNames, - isNewRiskScoreModuleInstalled - ); - const usersRiskByUserName: Record | undefined = - userRiskData?.hits.hits.reduce( - (acc, hit) => ({ - ...acc, - [hit._source?.user.name ?? '']: hit._source?.user?.risk?.calculated_level, - }), - {} - ); + const [riskByUserName, criticalityByUserName] = await Promise.all([ + getUserRiskData(esClient, spaceId, userNames, isNewRiskScoreModuleInstalled).then( + buildRecordFromAggs('user.name', 'user.risk.calculated_level') + ), + getUserCriticalityData(esClient, userNames).then( + buildRecordFromAggs('id_value', 'criticality_level') + ), + ]); - return usersRiskByUserName - ? edges.map(({ name, lastSeen, domain }) => ({ - name, - lastSeen, - domain, - risk: usersRiskByUserName[name ?? ''], - })) - : edges; + return edges.map(({ name, lastSeen, domain }) => ({ + name, + lastSeen, + domain, + risk: riskByUserName?.[name ?? ''] as RiskSeverity, + criticality: criticalityByUserName?.[name ?? ''], + })); } export async function getUserRiskData( @@ -151,3 +149,33 @@ export async function getUserRiskData( return undefined; } } + +export async function getUserCriticalityData(esClient: IScopedClusterClient, hostNames: string[]) { + try { + const criticalityResponse = await esClient.asCurrentUser.search( + buildAssetCriticalityQuery({ + defaultIndex: [getAssetCriticalityIndex('default')], // TODO:(@tiansivive) move to constant or import from somewhere else + filterQuery: { terms: { id_value: hostNames } }, + }) + ); + return criticalityResponse; + } catch (error) { + if (error?.meta?.body?.error?.type !== 'index_not_found_exception') { + throw error; + } + return undefined; + } +} + +const buildRecordFromAggs = + (key: string, path: string) => + ( + data: SearchResponse> | undefined + ): Record | undefined => + data?.hits.hits.reduce( + (acc, hit) => ({ + ...acc, + [_.get(hit._source, key) || '']: _.get(hit._source, path), + }), + {} + ); From b46f9d38678d84998d5aa81486a2dd27e42bd5ad Mon Sep 17 00:00:00 2001 From: Mykola Harmash Date: Thu, 20 Jun 2024 11:32:41 +0200 Subject: [PATCH 111/123] [Infra] Fix processes chart query time range (#186484) Closes https://github.com/elastic/sdh-kibana/issues/4739 ## Summary Fixes an issue with process chart query where it was fetching only for 1 minute while the chart was expecting data for 15 minites. The issue was that `query` was filtering the documents by the latest 1 minute while `date_histogram` is using `extended_bounds` to cover the last 15 minutes (relative the to provided `to` date). `extended_bounds` ensures that we return buckets for 15 minutes range even if some buckets are empty, but it does not expand the filter range from the `query` which is set to 1 minute, meaning the first 13 buckets were always empty. This change expands the `filter` query for the chart to 15 minutes. **After the change** ![CleanShot 2024-06-19 at 19 57 33@2x](https://github.com/elastic/kibana/assets/793851/5b828891-1f73-4b27-b73f-c48501bcf69b) --- .../infra/server/lib/host_details/process_list_chart.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/server/lib/host_details/process_list_chart.ts b/x-pack/plugins/observability_solution/infra/server/lib/host_details/process_list_chart.ts index befe8fc017ad49..95b51d07072c3d 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/host_details/process_list_chart.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/host_details/process_list_chart.ts @@ -19,6 +19,8 @@ export const getProcessListChart = async ( search: ESSearchClient, { hostTerm, indexPattern, to, command }: ProcessListAPIChartRequest ) => { + const from = to - 60 * 15 * 1000; // 15 minutes + const body = { size: 0, query: { @@ -27,7 +29,7 @@ export const getProcessListChart = async ( { range: { [TIMESTAMP_FIELD]: { - gte: to - 60 * 1000, // 1 minute + gte: from, lte: to, format: 'epoch_millis', }, @@ -64,7 +66,7 @@ export const getProcessListChart = async ( field: TIMESTAMP_FIELD, fixed_interval: '1m', extended_bounds: { - min: to - 60 * 15 * 1000, // 15 minutes, + min: from, max: to, }, }, From 1e1e35ba08c1066c17dbd482136cbbf63b22c116 Mon Sep 17 00:00:00 2001 From: Carlos Delgado <6339205+carlosdelest@users.noreply.github.com> Date: Thu, 20 Jun 2024 11:33:50 +0200 Subject: [PATCH 112/123] Add semantic query autocomplete support (#186408) --- .../console/server/lib/spec_definitions/js/query/dsl.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/console/server/lib/spec_definitions/js/query/dsl.ts b/src/plugins/console/server/lib/spec_definitions/js/query/dsl.ts index 273c5eab9c8893..219924b8771c42 100644 --- a/src/plugins/console/server/lib/spec_definitions/js/query/dsl.ts +++ b/src/plugins/console/server/lib/spec_definitions/js/query/dsl.ts @@ -526,6 +526,14 @@ export const query = (specService: SpecDefinitionsService) => { }, }, }, + semantic: { + __template: { + field: '', + query: '', + }, + field: '{field}', + query: '', + }, span_first: { __template: spanFirstTemplate, match: SPAN_QUERIES, From 85f12800bb80d959b3d1fb1c2d4c912b1a4e19c4 Mon Sep 17 00:00:00 2001 From: Faisal Kanout Date: Thu, 20 Jun 2024 14:16:16 +0200 Subject: [PATCH 113/123] [OBX-UI-MNGMT] Align the Metric rule charts by using Lens in Alert details page and Creation Rule flyout (#184950) ## Summary Fixes #184922 Fixes #184574 It uses the `RuleConditionChart`, a.k.a Lens chart, for the Metric Threshold rule. ### Implemented in both places: - Metric Alert Details page ![Screenshot 2024-06-10 at 16 12 43](https://github.com/elastic/kibana/assets/6838659/9d88d9b9-fe5d-4f8d-9e5a-538c52c58692) - Rule creation flyout ![Screenshot 2024-06-10 at 16 13 18](https://github.com/elastic/kibana/assets/6838659/8c9ca3b3-2fbf-4cfa-83c9-00278c5e8e77) --- .../alert_details_app_section.test.tsx.snap | 68 ++++++--- .../alert_details_app_section.test.tsx | 38 ++++- .../components/alert_details_app_section.tsx | 140 +++++++++++------- .../components/expression.tsx | 44 +++++- .../mocks/metric_threshold_rule.ts | 1 + .../infra/tsconfig.json | 4 +- .../alert_details_app_section.test.tsx | 4 +- .../alert_details_app_section.tsx | 4 +- .../custom_threshold_rule_expression.test.tsx | 2 +- .../custom_threshold_rule_expression.tsx | 2 +- .../rule_condition_chart/helpers.test.ts | 2 +- .../rule_condition_chart/helpers.ts | 12 +- .../painless_tinymath_parser.test.ts | 0 .../painless_tinymath_parser.ts | 0 .../rule_condition_chart.test.tsx | 16 +- .../rule_condition_chart.tsx | 140 ++++++++++++++++-- .../observability/public/index.ts | 3 + .../translations/translations/fr-FR.json | 3 - .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - 20 files changed, 354 insertions(+), 135 deletions(-) rename x-pack/plugins/observability_solution/observability/public/components/{custom_threshold/components => }/rule_condition_chart/helpers.test.ts (98%) rename x-pack/plugins/observability_solution/observability/public/components/{custom_threshold/components => }/rule_condition_chart/helpers.ts (85%) rename x-pack/plugins/observability_solution/observability/public/components/{custom_threshold/components => }/rule_condition_chart/painless_tinymath_parser.test.ts (100%) rename x-pack/plugins/observability_solution/observability/public/components/{custom_threshold/components => }/rule_condition_chart/painless_tinymath_parser.ts (100%) rename x-pack/plugins/observability_solution/observability/public/components/{custom_threshold/components => }/rule_condition_chart/rule_condition_chart.test.tsx (78%) rename x-pack/plugins/observability_solution/observability/public/components/{custom_threshold/components => }/rule_condition_chart/rule_condition_chart.tsx (71%) diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap index 72381f6e62d636..af8a5b3d8e0a96 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap +++ b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/__snapshots__/alert_details_app_section.test.tsx.snap @@ -3,37 +3,61 @@ exports[`AlertDetailsAppSection should render annotations 1`] = ` Array [ Object { + "additionalFilters": undefined, "annotations": Array [ - , - , + Object { + "color": "#BD271E", + "icon": "alert", + "id": "metric_threshold_alert_start_annotation", + "key": Object { + "timestamp": "2023-03-28T13:40:00.000Z", + "type": "point_in_time", + }, + "label": "Alert", + "type": "manual", + }, + Object { + "color": "#F04E9833", + "id": "metric_threshold_active_alert_range_annotation", + "key": Object { + "endTimestamp": "2024-06-13T07:00:33.381Z", + "timestamp": "2023-03-28T13:40:00.000Z", + "type": "range", + }, + "label": "Active alert", + "type": "manual", + }, ], - "chartType": "line", - "expression": Object { - "aggType": "count", + "chartOptions": Object { + "seriesType": "bar_stacked", + }, + "dataView": "index", + "groupBy": Array [ + "host.hostname", + ], + "metricExpression": Object { "comparator": ">", + "metrics": Array [ + Object { + "aggType": "count", + "field": "", + "name": "A", + }, + ], "threshold": Array [ 2000, ], "timeSize": 15, "timeUnit": "m", + "warningComparator": undefined, + "warningThreshold": undefined, + }, + "searchConfiguration": Object { + "query": Object { + "language": "", + "query": "", + }, }, - "filterQuery": undefined, - "groupBy": Array [ - "host.hostname", - ], - "groupInstance": Array [ - "host-1", - ], - "hideTitle": true, "timeRange": Object { "from": "2023-03-28T10:43:13.802Z", "to": "2023-03-29T13:14:09.581Z", diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx index eaf077684cf4da..5f8b99629eeb8d 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx +++ b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx @@ -16,15 +16,35 @@ import { buildMetricThresholdRule, } from '../mocks/metric_threshold_rule'; import { AlertDetailsAppSection } from './alert_details_app_section'; -import { ExpressionChart } from './expression_chart'; +import { RuleConditionChart } from '@kbn/observability-plugin/public'; +import { lensPluginMock } from '@kbn/lens-plugin/public/mocks'; const mockedChartStartContract = chartPluginMock.createStartContract(); +const mockedLensStartContract = lensPluginMock.createStartContract(); + +Date.now = jest.fn(() => new Date('2024-06-13T07:00:33.381Z').getTime()); + +jest.mock('../../../containers/metrics_source', () => ({ + useMetricsDataViewContext: () => ({ + metricsView: { dataViewReference: 'index' }, + }), + withSourceProvider: + (Component: React.FC) => + () => { + return function ComponentWithSourceProvider(props: ComponentProps) { + return
; + }; + }, +})); jest.mock('@kbn/observability-alert-details', () => ({ AlertAnnotation: () => {}, AlertActiveTimeRangeAnnotation: () => {}, })); - +jest.mock('@kbn/observability-alert-details', () => ({ + AlertAnnotation: () => {}, + AlertActiveTimeRangeAnnotation: () => {}, +})); jest.mock('@kbn/observability-get-padded-alert-time-range-util', () => ({ getPaddedAlertTimeRange: () => ({ from: '2023-03-28T10:43:13.802Z', @@ -32,8 +52,9 @@ jest.mock('@kbn/observability-get-padded-alert-time-range-util', () => ({ }), })); -jest.mock('./expression_chart', () => ({ - ExpressionChart: jest.fn(() =>
), +jest.mock('@kbn/observability-plugin/public', () => ({ + RuleConditionChart: jest.fn(() =>
), + getGroupFilters: jest.fn(), })); jest.mock('../../../hooks/use_kibana', () => ({ @@ -41,6 +62,7 @@ jest.mock('../../../hooks/use_kibana', () => ({ services: { ...mockCoreMock.createStart(), charts: mockedChartStartContract, + lens: mockedLensStartContract, }, }), })); @@ -74,11 +96,11 @@ describe('AlertDetailsAppSection', () => { }); it('should render annotations', async () => { - const mockedExpressionChart = jest.fn(() =>
); - (ExpressionChart as jest.Mock).mockImplementation(mockedExpressionChart); + const mockedRuleConditionChart = jest.fn(() =>
); + (RuleConditionChart as jest.Mock).mockImplementation(mockedRuleConditionChart); renderComponent(); - expect(mockedExpressionChart).toHaveBeenCalledTimes(3); - expect(mockedExpressionChart.mock.calls[0]).toMatchSnapshot(); + expect(mockedRuleConditionChart).toHaveBeenCalledTimes(3); + expect(mockedRuleConditionChart.mock.calls[0]).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx index bee0035f210c1e..78d908d85ad8c7 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx +++ b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx @@ -15,29 +15,32 @@ import { EuiPanel, EuiSpacer, EuiTitle, + transparentize, useEuiTheme, } from '@elastic/eui'; -import { AlertSummaryField, TopAlert } from '@kbn/observability-plugin/public'; +import chroma from 'chroma-js'; + +import { AlertSummaryField, RuleConditionChart, TopAlert } from '@kbn/observability-plugin/public'; import { ALERT_END, ALERT_START, ALERT_EVALUATION_VALUES, ALERT_GROUP } from '@kbn/rule-data-utils'; -import { Rule } from '@kbn/alerting-plugin/common'; -import { AlertAnnotation, AlertActiveTimeRangeAnnotation } from '@kbn/observability-alert-details'; +import { Rule, RuleTypeParams } from '@kbn/alerting-plugin/common'; import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; +import type { + EventAnnotationConfig, + PointInTimeEventAnnotationConfig, + RangeEventAnnotationConfig, +} from '@kbn/event-annotation-common'; + +import { getGroupFilters } from '@kbn/observability-plugin/public'; +import type { GenericAggType } from '@kbn/observability-plugin/public'; import { metricValueFormatter } from '../../../../common/alerting/metrics/metric_value_formatter'; import { Threshold } from '../../common/components/threshold'; -import { withSourceProvider } from '../../../containers/metrics_source'; +import { useMetricsDataViewContext, withSourceProvider } from '../../../containers/metrics_source'; import { generateUniqueKey } from '../lib/generate_unique_key'; -import { MetricsExplorerChartType } from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; -import { MetricThresholdRuleTypeParams } from '..'; -import { ExpressionChart } from './expression_chart'; +import { AlertParams } from '../types'; // TODO Use a generic props for app sections https://github.com/elastic/kibana/issues/152690 -export type MetricThresholdRule = Rule< - MetricThresholdRuleTypeParams & { - filterQueryText?: string; - groupBy?: string | string[]; - } ->; +export type MetricThresholdRule = Rule; interface Group { field: string; @@ -51,41 +54,49 @@ interface MetricThresholdAlertField { export type MetricThresholdAlert = TopAlert; -const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm'; -const ALERT_START_ANNOTATION_ID = 'alert_start_annotation'; -const ALERT_TIME_RANGE_ANNOTATION_ID = 'alert_time_range_annotation'; - interface AppSectionProps { alert: MetricThresholdAlert; rule: MetricThresholdRule; setAlertSummaryFields: React.Dispatch>; } -export function AlertDetailsAppSection({ alert, rule }: AppSectionProps) { - const { uiSettings, charts } = useKibanaContextForPlugin().services; +export function AlertDetailsAppSection({ alert, rule, setAlertSummaryFields }: AppSectionProps) { + const { charts } = useKibanaContextForPlugin().services; const { euiTheme } = useEuiTheme(); - const groupInstance = alert.fields[ALERT_GROUP]?.map((group: Group) => group.value); - + const groups = alert.fields[ALERT_GROUP]; + const { metricsView } = useMetricsDataViewContext(); const chartProps = { baseTheme: charts.theme.useChartsBaseTheme(), }; - const alertEnd = alert.fields[ALERT_END] ? moment(alert.fields[ALERT_END]).valueOf() : undefined; - const annotations = [ - , - , - ]; + const alertEnd = alert.fields[ALERT_END]; + const alertStart = alert.fields[ALERT_START]; + + const alertStartAnnotation: PointInTimeEventAnnotationConfig = { + label: 'Alert', + type: 'manual', + key: { + type: 'point_in_time', + timestamp: alertStart!, + }, + color: euiTheme.colors.danger, + icon: 'alert', + id: 'metric_threshold_alert_start_annotation', + }; + + const alertRangeAnnotation: RangeEventAnnotationConfig = { + label: `${alertEnd ? 'Alert duration' : 'Active alert'}`, + type: 'manual', + key: { + type: 'range', + timestamp: alertStart!, + endTimestamp: alertEnd ?? moment().toISOString(), + }, + color: chroma(transparentize('#F04E981A', 0.2)).hex().toUpperCase(), + id: `metric_threshold_${alertEnd ? 'recovered' : 'active'}_alert_range_annotation`, + }; + + const annotations: EventAnnotationConfig[] = []; + annotations.push(alertStartAnnotation, alertRangeAnnotation); return !!rule.params.criteria ? ( @@ -94,10 +105,25 @@ export function AlertDetailsAppSection({ alert, rule }: AppSectionProps) { alert.fields[ALERT_START]!, alert.fields[ALERT_END], { - size: criterion.timeSize, - unit: criterion.timeUnit, + size: criterion.timeSize!, + unit: criterion.timeUnit!, } ); + let metricExpression = [ + { + aggType: criterion.aggType as GenericAggType, + name: String.fromCharCode('A'.charCodeAt(0) + index), + field: criterion.metric || '', + }, + ]; + if (criterion.customMetrics) { + metricExpression = criterion.customMetrics.map((metric) => ({ + name: metric.name, + aggType: metric.aggType as GenericAggType, + field: metric.field || '', + filter: metric.filter, + })); + } return ( @@ -135,16 +161,30 @@ export function AlertDetailsAppSection({ alert, rule }: AppSectionProps) { /> - + {metricsView && ( + + )} diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/expression.tsx b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/expression.tsx index 191c6ed8cd847c..9eaf5e2bd7b459 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/expression.tsx +++ b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/components/expression.tsx @@ -28,6 +28,7 @@ import { } from '@kbn/triggers-actions-ui-plugin/public'; import { TimeUnitChar } from '@kbn/observability-plugin/common/utils/formatters/duration'; import { COMPARATORS } from '@kbn/alerting-comparators'; +import { GenericAggType, RuleConditionChart } from '@kbn/observability-plugin/public'; import { Aggregators, QUERY_INVALID } from '../../../../common/alerting/metrics'; import { useMetricsDataViewContext, @@ -40,7 +41,6 @@ import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer import { MetricsExplorerOptions } from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; import { convertKueryToElasticSearchQuery } from '../../../utils/kuery'; import { AlertContextMeta, AlertParams, MetricExpression } from '../types'; -import { ExpressionChart } from './expression_chart'; import { ExpressionRow } from './expression_row'; const FILTER_TYPING_DEBOUNCE_MS = 500; @@ -69,7 +69,6 @@ export const Expressions: React.FC = (props) => { const { docLinks } = useKibanaContextForPlugin().services; const { source } = useSourceContext(); const { metricsView } = useMetricsDataViewContext(); - const [timeSize, setTimeSize] = useState(1); const [timeUnit, setTimeUnit] = useState('m'); @@ -304,8 +303,24 @@ export const Expressions: React.FC = (props) => {

- {ruleParams.criteria && + {metricsView && ruleParams.criteria.map((e, idx) => { + let metricExpression = [ + { + aggType: e.aggType as GenericAggType, + // RuleConditionChart uses A,B,C etc in its parser to identify multiple conditions + name: String.fromCharCode('A'.charCodeAt(0) + idx), + field: e.metric || '', + }, + ]; + if (e.customMetrics) { + metricExpression = e.customMetrics.map((metric) => ({ + name: metric.name, + aggType: metric.aggType as GenericAggType, + field: metric.field || '', + filter: metric.filter, + })); + } return ( 1) || false} @@ -317,9 +332,26 @@ export const Expressions: React.FC = (props) => { errors={(errors[idx] as IErrorObject) || emptyError} expression={e || {}} > - diff --git a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/mocks/metric_threshold_rule.ts b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/mocks/metric_threshold_rule.ts index 0ef6478ff12d7a..f7ec9022b4cad5 100644 --- a/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/mocks/metric_threshold_rule.ts +++ b/x-pack/plugins/observability_solution/infra/public/alerting/metric_threshold/mocks/metric_threshold_rule.ts @@ -87,6 +87,7 @@ export const buildMetricThresholdRule = ( filterQuery: '{"bool":{"filter":[{"bool":{"should":[{"term":{"host.hostname":{"value":"Users-System.local"}}}],"minimum_should_match":1}},{"bool":{"should":[{"term":{"service.type":{"value":"system"}}}],"minimum_should_match":1}}]}}', groupBy: ['host.hostname'], + sourceId: 'sourceId', }, monitoring: { run: { diff --git a/x-pack/plugins/observability_solution/infra/tsconfig.json b/x-pack/plugins/observability_solution/infra/tsconfig.json index d1d1f0542da0a1..f23c9f7b30c349 100644 --- a/x-pack/plugins/observability_solution/infra/tsconfig.json +++ b/x-pack/plugins/observability_solution/infra/tsconfig.json @@ -63,7 +63,6 @@ "@kbn/shared-ux-router", "@kbn/shared-ux-link-redirect-app", "@kbn/discover-plugin", - "@kbn/observability-alert-details", "@kbn/observability-shared-plugin", "@kbn/observability-ai-assistant-plugin", "@kbn/ui-theme", @@ -105,7 +104,8 @@ "@kbn/react-kibana-context-theme", "@kbn/presentation-publishing", "@kbn/presentation-containers", - "@kbn/deeplinks-observability" + "@kbn/deeplinks-observability", + "@kbn/event-annotation-common" ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx index 35104fd199d3ab..a98a519a1606a2 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.test.tsx @@ -18,7 +18,7 @@ import { buildCustomThresholdRule, } from '../../mocks/custom_threshold_rule'; import { CustomThresholdAlertFields } from '../../types'; -import { RuleConditionChart } from '../rule_condition_chart/rule_condition_chart'; +import { RuleConditionChart } from '../../../rule_condition_chart/rule_condition_chart'; import { CustomThresholdAlert } from '../types'; import AlertDetailsAppSection from './alert_details_app_section'; @@ -47,7 +47,7 @@ jest.mock('@kbn/observability-get-padded-alert-time-range-util', () => ({ }), })); -jest.mock('../rule_condition_chart/rule_condition_chart', () => ({ +jest.mock('../../../rule_condition_chart/rule_condition_chart', () => ({ RuleConditionChart: jest.fn(() =>
), })); diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx index 3a065d6e06f3e6..83aa8cf2a35d30 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/alert_details_app_section/alert_details_app_section.tsx @@ -31,16 +31,16 @@ import type { import moment from 'moment'; import { LOGS_EXPLORER_LOCATOR_ID, LogsExplorerLocatorParams } from '@kbn/deeplinks-observability'; import { TimeRange } from '@kbn/es-query'; +import { getGroupFilters } from '../../../../../common/custom_threshold_rule/helpers/get_group'; import { useLicense } from '../../../../hooks/use_license'; import { useKibana } from '../../../../utils/kibana_react'; -import { getGroupFilters } from '../../../../../common/custom_threshold_rule/helpers/get_group'; import { metricValueFormatter } from '../../../../../common/custom_threshold_rule/metric_value_formatter'; import { AlertSummaryField } from '../../../..'; import { AlertParams } from '../../types'; import { Threshold } from '../custom_threshold'; import { CustomThresholdRule, CustomThresholdAlert } from '../types'; import { LogRateAnalysis } from './log_rate_analysis'; -import { RuleConditionChart } from '../rule_condition_chart/rule_condition_chart'; +import { RuleConditionChart } from '../../../rule_condition_chart/rule_condition_chart'; import { getViewInAppUrl } from '../../../../../common/custom_threshold_rule/get_view_in_app_url'; import { SearchConfigurationWithExtractedReferenceType } from '../../../../../common/custom_threshold_rule/types'; import { generateChartTitleAndTooltip } from './helpers/generate_chart_title_and_tooltip'; diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx index 02c428ccf36984..62580b3a89f82b 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx @@ -21,7 +21,7 @@ import Expressions from './custom_threshold_rule_expression'; import { AlertParams, CustomThresholdPrefillOptions } from './types'; jest.mock('../../utils/kibana_react'); -jest.mock('./components/rule_condition_chart/rule_condition_chart', () => ({ +jest.mock('../rule_condition_chart/rule_condition_chart', () => ({ RuleConditionChart: jest.fn(() =>
), })); diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx index fab9568b080a9c..0db9c2f048e113 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx @@ -42,7 +42,7 @@ import { TimeUnitChar } from '../../../common/utils/formatters/duration'; import { AlertContextMeta, AlertParams, MetricExpression } from './types'; import { ExpressionRow } from './components/expression_row'; import { MetricsExplorerFields, GroupBy } from './components/group_by'; -import { RuleConditionChart as PreviewChart } from './components/rule_condition_chart/rule_condition_chart'; +import { RuleConditionChart as PreviewChart } from '../rule_condition_chart/rule_condition_chart'; import { getSearchConfiguration } from './helpers/get_search_configuration'; const FILTER_TYPING_DEBOUNCE_MS = 500; diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/helpers.test.ts b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.test.ts similarity index 98% rename from x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/helpers.test.ts rename to x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.test.ts index 4211907b5d4a01..044b57c64da28d 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/helpers.test.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.test.ts @@ -7,7 +7,7 @@ import { Aggregators, CustomThresholdExpressionMetric, -} from '../../../../../common/custom_threshold_rule/types'; +} from '../../../common/custom_threshold_rule/types'; import { getBufferThreshold, getLensOperationFromRuleMetric, lensFieldFormatter } from './helpers'; const useCases = [ [ diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/helpers.ts b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.ts similarity index 85% rename from x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/helpers.ts rename to x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.ts index 1875af6ceb93ee..7cedf19d0b6606 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/helpers.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.ts @@ -5,12 +5,10 @@ * 2.0. */ -import { - Aggregators, - CustomThresholdExpressionMetric, -} from '../../../../../common/custom_threshold_rule/types'; +import { Aggregators } from '../../../common/custom_threshold_rule/types'; +import { GenericMetric } from './rule_condition_chart'; -export const getLensOperationFromRuleMetric = (metric: CustomThresholdExpressionMetric): string => { +export const getLensOperationFromRuleMetric = (metric: GenericMetric): string => { const { aggType, field, filter } = metric; let operation: string = aggType; const operationArgs: string[] = []; @@ -56,7 +54,7 @@ export const LensFieldFormat = { } as const; export const lensFieldFormatter = ( - metrics: CustomThresholdExpressionMetric[] + metrics: GenericMetric[] ): typeof LensFieldFormat[keyof typeof LensFieldFormat] => { if (metrics.length < 1 || !metrics[0].field) return LensFieldFormat.NUMBER; const firstMetricField = metrics[0].field; @@ -65,5 +63,5 @@ export const lensFieldFormatter = ( return LensFieldFormat.NUMBER; }; -export const isRate = (metrics: CustomThresholdExpressionMetric[]): boolean => +export const isRate = (metrics: GenericMetric[]): boolean => Boolean(metrics.length > 0 && metrics[0].aggType === Aggregators.RATE); diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.test.ts b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/painless_tinymath_parser.test.ts similarity index 100% rename from x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.test.ts rename to x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/painless_tinymath_parser.test.ts diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.ts b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/painless_tinymath_parser.ts similarity index 100% rename from x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.ts rename to x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/painless_tinymath_parser.ts diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/rule_condition_chart.test.tsx b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.test.tsx similarity index 78% rename from x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/rule_condition_chart.test.tsx rename to x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.test.tsx index d164e6670b4a7e..ac0624265be0b7 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/rule_condition_chart.test.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.test.tsx @@ -13,13 +13,12 @@ import { COMPARATORS } from '@kbn/alerting-comparators'; import { Aggregators, CustomThresholdSearchSourceFields, -} from '../../../../../common/custom_threshold_rule/types'; -import { useKibana } from '../../../../utils/kibana_react'; -import { kibanaStartMock } from '../../../../utils/kibana_react.mock'; -import { MetricExpression } from '../../types'; -import { RuleConditionChart } from './rule_condition_chart'; +} from '../../../common/custom_threshold_rule/types'; +import { useKibana } from '../../utils/kibana_react'; +import { kibanaStartMock } from '../../utils/kibana_react.mock'; +import { RuleConditionChart, RuleConditionChartExpressions } from './rule_condition_chart'; -jest.mock('../../../../utils/kibana_react'); +jest.mock('../../utils/kibana_react'); const useKibanaMock = useKibana as jest.Mock; @@ -34,7 +33,7 @@ describe('Rule condition chart', () => { jest.clearAllMocks(); mockKibana(); }); - async function setup(expression: MetricExpression, dataView?: DataView) { + async function setup(expression: RuleConditionChartExpressions, dataView?: DataView) { const wrapper = mountWithIntl( { } it('should display no data message', async () => { - const expression: MetricExpression = { + const expression: RuleConditionChartExpressions = { metrics: [ { name: 'A', @@ -67,7 +66,6 @@ describe('Rule condition chart', () => { ], timeSize: 1, timeUnit: 'm', - sourceId: 'default', threshold: [1], comparator: COMPARATORS.GREATER_THAN_OR_EQUALS, }; diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/rule_condition_chart.tsx b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.tsx similarity index 71% rename from x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/rule_condition_chart.tsx rename to x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.tsx index 1e326e3fa5f6de..a8710004876ffa 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/rule_condition_chart/rule_condition_chart.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.tsx @@ -26,10 +26,12 @@ import { i18n } from '@kbn/i18n'; import { TimeRange } from '@kbn/es-query'; import { EventAnnotationConfig } from '@kbn/event-annotation-common'; import { COMPARATORS } from '@kbn/alerting-comparators'; -import { EventsAsUnit } from '../../../../../common/constants'; -import { CustomThresholdSearchSourceFields } from '../../../../../common/custom_threshold_rule/types'; -import { useKibana } from '../../../../utils/kibana_react'; -import { MetricExpression } from '../../types'; +import { SerializedSearchSourceFields } from '@kbn/data-plugin/common'; +import { TimeUnitChar } from '../../../common'; +import { LEGACY_COMPARATORS } from '../../../common/utils/convert_legacy_outside_comparator'; +import { EventsAsUnit } from '../../../common/constants'; +import { Aggregators } from '../../../common/custom_threshold_rule/types'; +import { useKibana } from '../../utils/kibana_react'; import { AggMap, PainlessTinyMathParser } from './painless_tinymath_parser'; import { lensFieldFormatter, @@ -38,15 +40,38 @@ import { isRate, LensFieldFormat, } from './helpers'; - interface ChartOptions { seriesType?: SeriesType; interval?: string; } +interface GenericSearchSourceFields extends SerializedSearchSourceFields { + query?: Query; + filter?: Array>; +} + +export type GenericAggType = Aggregators | 'custom'; + +export interface GenericMetric { + aggType: GenericAggType; + name: string; + field?: string; + filter?: string; +} + +export interface RuleConditionChartExpressions { + metrics: GenericMetric[]; + threshold: number[]; + comparator: COMPARATORS | LEGACY_COMPARATORS; + warningThreshold?: number[]; + warningComparator?: COMPARATORS | LEGACY_COMPARATORS; + timeSize?: number; + timeUnit?: TimeUnitChar; + equation?: string; +} interface RuleConditionChartProps { - metricExpression: MetricExpression; - searchConfiguration: CustomThresholdSearchSourceFields; + metricExpression: RuleConditionChartExpressions; + searchConfiguration: GenericSearchSourceFields; dataView?: DataView; groupBy?: string | string[]; error?: IErrorObject; @@ -76,11 +101,22 @@ export function RuleConditionChart({ services: { lens }, } = useKibana(); const { euiTheme } = useEuiTheme(); - const { metrics, timeSize, timeUnit, threshold, comparator, equation } = metricExpression; + const { + metrics, + timeSize, + timeUnit, + threshold, + comparator, + equation, + warningComparator, + warningThreshold, + } = metricExpression; const [attributes, setAttributes] = useState(); const [aggMap, setAggMap] = useState(); const [formula, setFormula] = useState(''); const [thresholdReferenceLine, setThresholdReferenceLine] = useState(); + const [warningThresholdReferenceLine, setWarningThresholdReferenceLine] = + useState(); const [alertAnnotation, setAlertAnnotation] = useState(); const [chartLoading, setChartLoading] = useState(false); const filters = [...(searchConfiguration.filter || []), ...additionalFilters]; @@ -98,13 +134,13 @@ export function RuleConditionChart({ const paragraphElements = errorDiv.querySelectorAll('p'); if (!paragraphElements || paragraphElements.length < 2) return; paragraphElements[0].innerText = i18n.translate( - 'xpack.observability.customThreshold.rule..charts.error_equation.title', + 'xpack.observability.ruleCondition.chart.error_equation.title', { defaultMessage: 'An error occurred while rendering the chart', } ); paragraphElements[1].innerText = i18n.translate( - 'xpack.observability.customThreshold.rule..charts.error_equation.description', + 'xpack.observability.ruleCondition.chart.error_equation.description', { defaultMessage: 'Check the rule equation.', } @@ -113,6 +149,77 @@ export function RuleConditionChart({ }); }, [chartLoading, attributes]); + // Build the warning threshold reference line + useEffect(() => { + if (!warningThreshold) { + if (warningThresholdReferenceLine?.length) { + setWarningThresholdReferenceLine([]); + } + return; + } + const refLayers = []; + if ( + warningComparator === COMPARATORS.NOT_BETWEEN || + (warningComparator === COMPARATORS.BETWEEN && warningThreshold.length === 2) + ) { + const refLineStart = new XYReferenceLinesLayer({ + data: [ + { + value: (warningThreshold[0] || 0).toString(), + color: euiTheme.colors.warning, + fill: warningComparator === COMPARATORS.NOT_BETWEEN ? 'below' : 'none', + }, + ], + }); + const refLineEnd = new XYReferenceLinesLayer({ + data: [ + { + value: (warningThreshold[1] || 0).toString(), + color: euiTheme.colors.warning, + fill: warningComparator === COMPARATORS.NOT_BETWEEN ? 'above' : 'none', + }, + ], + }); + + refLayers.push(refLineStart, refLineEnd); + } else { + let fill: FillStyle = 'above'; + if ( + warningComparator === COMPARATORS.LESS_THAN || + warningComparator === COMPARATORS.LESS_THAN_OR_EQUALS + ) { + fill = 'below'; + } + const warningThresholdRefLine = new XYReferenceLinesLayer({ + data: [ + { + value: (warningThreshold[0] || 0).toString(), + color: euiTheme.colors.warning, + fill, + }, + ], + }); + // A transparent line to add extra buffer at the top of threshold + const bufferRefLine = new XYReferenceLinesLayer({ + data: [ + { + value: getBufferThreshold(warningThreshold[0]), + color: 'transparent', + fill, + }, + ], + }); + refLayers.push(warningThresholdRefLine, bufferRefLine); + } + setWarningThresholdReferenceLine(refLayers); + }, [ + warningThreshold, + warningComparator, + euiTheme.colors.warning, + metrics, + warningThresholdReferenceLine?.length, + ]); + // Build the threshold reference line useEffect(() => { if (!threshold) return; @@ -225,7 +332,7 @@ export function RuleConditionChart({ const baseLayer = { type: 'formula', value: formula, - label: 'Custom Threshold', + label: formula, groupBy, format: { id: formatId, @@ -272,6 +379,9 @@ export function RuleConditionChart({ const layers: Array = [ xyDataLayer, ]; + if (warningThresholdReferenceLine) { + layers.push(...warningThresholdReferenceLine); + } if (thresholdReferenceLine) { layers.push(...thresholdReferenceLine); } @@ -311,13 +421,14 @@ export function RuleConditionChart({ timeSize, timeUnit, seriesType, + warningThresholdReferenceLine, ]); if ( !dataView || !attributes || error?.equation || - Object.keys(error?.metrics || {}).length !== 0 || + Object.keys(error?.metrics || error?.metric || {}).length !== 0 || !timeSize || !timeRange ) { @@ -329,7 +440,7 @@ export function RuleConditionChart({ data-test-subj="thresholdRuleNoChartData" body={ ); } - return (
Date: Thu, 20 Jun 2024 06:56:17 -0700 Subject: [PATCH 114/123] Onboard Synthetics Monitor Status rule type with FAAD (#186214) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Towards: https://github.com/elastic/kibana/issues/169867 This PR onboards the Synthetics Monitor Status rule type with FAAD. ### To verify I can't get the rule to alert, so I modified the status check to report the monitor as down. If you know of an easier way pls let me know 🙂 1. Create a [monitor](http://localhost:5601/app/synthetics/monitors), by default creating a monitor creates a rule. 2. Click on the monitor and grab the id and locationId from the url 3. Go to [the status check code](https://github.com/elastic/kibana/blob/main/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts#L208) and replace the object that is returned with the following using the id and locationId you got from the monitor. ``` { up: 0, down: 1, pending: 0, upConfigs: {}, pendingConfigs: {}, downConfigs: { '${id}-${locationId}': { configId: '${id}', monitorQueryId: '${id}', status: 'down', locationId: '${locationId}', ping: { '@timestamp': new Date().toISOString(), state: { id: 'test-state', }, monitor: { name: 'test-monitor', }, observer: { name: 'test-monitor', }, } as any, timestamp: new Date().toISOString(), }, }, enabledMonitorQueryIds: ['${id}'], }; ``` 5. Your rule should create an alert and should saved it in `.internal.alerts-observability.uptime.alerts-default-000001` Example: ``` GET .internal.alerts-*/_search ``` 6. Recover repeating step 3 using ``` { up: 1, down: 0, pending: 0, downConfigs: {}, pendingConfigs: {}, upConfigs: { '${id}-${locationId}': { configId: '${id}', monitorQueryId: '${id}', status: 'down', locationId: '${locationId}', ping: { '@timestamp': new Date().toISOString(), state: { id: 'test-state', }, monitor: { name: 'test-monitor', }, observer: { name: 'test-monitor', }, } as any, timestamp: new Date().toISOString(), }, }, enabledMonitorQueryIds: ['${id}'], }; ``` 8. The alert should be recovered and the AAD in the above index should be updated `kibana.alert.status: recovered`. --- .../server/alert_rules/common.test.ts | 215 ++++++++++-------- .../synthetics/server/alert_rules/common.ts | 42 ++-- .../status_rule/monitor_status_rule.ts | 93 ++++---- .../synthetics/server/server.ts | 15 +- 4 files changed, 206 insertions(+), 159 deletions(-) diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts index 2edcd37a959276..58227c38cfb540 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; import { IBasePath } from '@kbn/core/server'; import { updateState, setRecoveredAlertsContext } from './common'; import { SyntheticsCommonState } from '../../common/runtime_types/alert_rules/common'; @@ -186,8 +185,6 @@ describe('updateState', () => { }); describe('setRecoveredAlertsContext', () => { - const { alertFactory } = alertsMock.createRuleExecutorServices(); - const { getRecoveredAlerts } = alertFactory.done(); const alertUuid = 'alert-id'; const location = 'US Central'; const configId = '12345'; @@ -195,7 +192,6 @@ describe('setRecoveredAlertsContext', () => { const basePath = { publicBaseUrl: 'https://localhost:5601', } as IBasePath; - const getAlertUuid = () => alertUuid; const upConfigs = { [idWithLocation]: { @@ -219,17 +215,26 @@ describe('setRecoveredAlertsContext', () => { }; it('sets context correctly when monitor is deleted', () => { - const setContext = jest.fn(); - getRecoveredAlerts.mockReturnValue([ - { - getId: () => alertUuid, - getState: () => ({ - idWithLocation, - monitorName: 'test-monitor', - }), - setContext, - }, - ]); + const alertsClientMock = { + report: jest.fn(), + getAlertLimitValue: jest.fn().mockReturnValue(10), + setAlertLimitReached: jest.fn(), + getRecoveredAlerts: jest.fn().mockReturnValue([ + { + alert: { + getId: () => alertUuid, + getState: () => ({ + idWithLocation, + monitorName: 'test-monitor', + }), + setContext: jest.fn(), + getUuid: () => alertUuid, + }, + }, + ]), + setAlertData: jest.fn(), + isTrackedAlert: jest.fn(), + }; const staleDownConfigs = { [idWithLocation]: { configId, @@ -250,45 +255,56 @@ describe('setRecoveredAlertsContext', () => { }, }; setRecoveredAlertsContext({ - alertFactory, + alertsClient: alertsClientMock, basePath, - getAlertUuid, spaceId: 'default', staleDownConfigs, upConfigs: {}, dateFormat, tz: 'UTC', }); - expect(setContext).toBeCalledWith({ - checkedAt: 'Feb 26, 2023 @ 00:00:00.000', - configId: '12345', - idWithLocation, - linkMessage: '', - alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', - monitorName: 'test-monitor', - recoveryReason: 'the monitor has been deleted', - recoveryStatus: 'has been deleted', - monitorUrl: '(unavailable)', - monitorUrlLabel: 'URL', - reason: - 'Monitor "test-monitor" from Unnamed-location is recovered. Checked at February 25, 2023 7:00 PM.', - stateId: '123456', - status: 'recovered', + expect(alertsClientMock.setAlertData).toBeCalledWith({ + id: 'alert-id', + context: { + checkedAt: 'Feb 26, 2023 @ 00:00:00.000', + configId: '12345', + idWithLocation, + linkMessage: '', + alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', + monitorName: 'test-monitor', + recoveryReason: 'the monitor has been deleted', + recoveryStatus: 'has been deleted', + monitorUrl: '(unavailable)', + monitorUrlLabel: 'URL', + reason: + 'Monitor "test-monitor" from Unnamed-location is recovered. Checked at February 25, 2023 7:00 PM.', + stateId: '123456', + status: 'recovered', + }, }); }); it('sets context correctly when location is removed', () => { - const setContext = jest.fn(); - getRecoveredAlerts.mockReturnValue([ - { - getId: () => alertUuid, - getState: () => ({ - idWithLocation, - monitorName: 'test-monitor', - }), - setContext, - }, - ]); + const alertsClientMock = { + report: jest.fn(), + getAlertLimitValue: jest.fn().mockReturnValue(10), + setAlertLimitReached: jest.fn(), + getRecoveredAlerts: jest.fn().mockReturnValue([ + { + alert: { + getId: () => alertUuid, + getState: () => ({ + idWithLocation, + monitorName: 'test-monitor', + }), + setContext: jest.fn(), + getUuid: () => alertUuid, + }, + }, + ]), + setAlertData: jest.fn(), + isTrackedAlert: jest.fn(), + }; const staleDownConfigs = { [idWithLocation]: { configId, @@ -309,47 +325,58 @@ describe('setRecoveredAlertsContext', () => { }, }; setRecoveredAlertsContext({ - alertFactory, + alertsClient: alertsClientMock, basePath, - getAlertUuid, spaceId: 'default', staleDownConfigs, upConfigs: {}, dateFormat, tz: 'UTC', }); - expect(setContext).toBeCalledWith({ - configId: '12345', - checkedAt: 'Feb 26, 2023 @ 00:00:00.000', - monitorUrl: '(unavailable)', - reason: - 'Monitor "test-monitor" from Unnamed-location is recovered. Checked at February 25, 2023 7:00 PM.', - idWithLocation, - linkMessage: '', - alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', - monitorName: 'test-monitor', - recoveryReason: 'this location has been removed from the monitor', - recoveryStatus: 'has recovered', - stateId: '123456', - status: 'recovered', - monitorUrlLabel: 'URL', + expect(alertsClientMock.setAlertData).toBeCalledWith({ + id: 'alert-id', + context: { + configId: '12345', + checkedAt: 'Feb 26, 2023 @ 00:00:00.000', + monitorUrl: '(unavailable)', + reason: + 'Monitor "test-monitor" from Unnamed-location is recovered. Checked at February 25, 2023 7:00 PM.', + idWithLocation, + linkMessage: '', + alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', + monitorName: 'test-monitor', + recoveryReason: 'this location has been removed from the monitor', + recoveryStatus: 'has recovered', + stateId: '123456', + status: 'recovered', + monitorUrlLabel: 'URL', + }, }); }); it('sets context correctly when monitor is up', () => { - const setContext = jest.fn(); - getRecoveredAlerts.mockReturnValue([ - { - getId: () => alertUuid, - getState: () => ({ - idWithLocation, - monitorName: 'test-monitor', - locationId: 'us_west', - configId: '12345-67891', - }), - setContext, - }, - ]); + const alertsClientMock = { + report: jest.fn(), + getAlertLimitValue: jest.fn().mockReturnValue(10), + setAlertLimitReached: jest.fn(), + getRecoveredAlerts: jest.fn().mockReturnValue([ + { + alert: { + getId: () => alertUuid, + getState: () => ({ + idWithLocation, + monitorName: 'test-monitor', + locationId: 'us_west', + configId: '12345-67891', + }), + setContext: jest.fn(), + getUuid: () => alertUuid, + }, + }, + ]), + setAlertData: jest.fn(), + isTrackedAlert: jest.fn(), + }; const staleDownConfigs = { [idWithLocation]: { configId, @@ -370,33 +397,35 @@ describe('setRecoveredAlertsContext', () => { }, }; setRecoveredAlertsContext({ - alertFactory, + alertsClient: alertsClientMock, basePath, - getAlertUuid, spaceId: 'default', staleDownConfigs, upConfigs, dateFormat, tz: 'UTC', }); - expect(setContext).toBeCalledWith({ - configId: '12345-67891', - idWithLocation, - alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', - monitorName: 'test-monitor', - status: 'up', - recoveryReason: - 'the monitor is now up again. It ran successfully at Feb 26, 2023 @ 00:00:00.000', - recoveryStatus: 'is now up', - locationId: 'us_west', - checkedAt: 'Feb 26, 2023 @ 00:00:00.000', - linkMessage: - '- Link: https://localhost:5601/app/synthetics/monitor/12345-67891/errors/123456?locationId=us_west', - monitorUrl: '(unavailable)', - monitorUrlLabel: 'URL', - reason: - 'Monitor "test-monitor" from Unnamed-location is recovered. Checked at February 25, 2023 7:00 PM.', - stateId: null, + expect(alertsClientMock.setAlertData).toBeCalledWith({ + id: 'alert-id', + context: { + configId: '12345-67891', + idWithLocation, + alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', + monitorName: 'test-monitor', + status: 'up', + recoveryReason: + 'the monitor is now up again. It ran successfully at Feb 26, 2023 @ 00:00:00.000', + recoveryStatus: 'is now up', + locationId: 'us_west', + checkedAt: 'Feb 26, 2023 @ 00:00:00.000', + linkMessage: + '- Link: https://localhost:5601/app/synthetics/monitor/12345-67891/errors/123456?locationId=us_west', + monitorUrl: '(unavailable)', + monitorUrlLabel: 'URL', + reason: + 'Monitor "test-monitor" from Unnamed-location is recovered. Checked at February 25, 2023 7:00 PM.', + stateId: null, + }, }); }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts index dc8bb9c25afe2f..5bb366001f0fb6 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts @@ -8,13 +8,22 @@ import moment, { Moment } from 'moment'; import { isRight } from 'fp-ts/lib/Either'; import Mustache from 'mustache'; import { IBasePath } from '@kbn/core/server'; -import { IRuleTypeAlerts, RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { + IRuleTypeAlerts, + ActionGroupIdsOf, + AlertInstanceContext as AlertContext, + AlertInstanceState as AlertState, +} from '@kbn/alerting-plugin/server'; import { addSpaceIdToPath } from '@kbn/spaces-plugin/common'; import { i18n } from '@kbn/i18n'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; -import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils'; +import { legacyExperimentalFieldMap, ObservabilityUptimeAlert } from '@kbn/alerts-as-data-utils'; +import { PublicAlertsClient } from '@kbn/alerting-plugin/server/alerts_client/types'; import { combineFiltersAndUserSearch, stringifyKueries } from '../../common/lib'; -import { SYNTHETICS_RULE_TYPES_ALERT_CONTEXT } from '../../common/constants/synthetics_alerts'; +import { + MonitorStatusActionGroup, + SYNTHETICS_RULE_TYPES_ALERT_CONTEXT, +} from '../../common/constants/synthetics_alerts'; import { uptimeRuleFieldMap } from '../../common/rules/uptime_rule_field_map'; import { getUptimeIndexPattern, @@ -26,7 +35,6 @@ import { getMonitorSummary } from './status_rule/message_utils'; import { SyntheticsCommonState, SyntheticsCommonStateCodec, - SyntheticsMonitorStatusAlertState, } from '../../common/runtime_types/alert_rules/common'; import { getSyntheticsErrorRouteFromMonitorId } from '../../common/utils/get_synthetics_monitor_url'; import { ALERT_DETAILS_URL, RECOVERY_REASON } from './action_variables'; @@ -154,30 +162,33 @@ export const getErrorDuration = (startedAt: Moment, endsAt: Moment) => { }; export const setRecoveredAlertsContext = ({ - alertFactory, + alertsClient, basePath, - getAlertUuid, spaceId, staleDownConfigs, upConfigs, dateFormat, tz, }: { - alertFactory: RuleExecutorServices['alertFactory']; + alertsClient: PublicAlertsClient< + ObservabilityUptimeAlert, + AlertState, + AlertContext, + ActionGroupIdsOf + >; basePath?: IBasePath; - getAlertUuid?: (alertId: string) => string | null; spaceId?: string; staleDownConfigs: AlertOverviewStatus['staleDownConfigs']; upConfigs: AlertOverviewStatus['upConfigs']; dateFormat: string; tz: string; }) => { - const { getRecoveredAlerts } = alertFactory.done(); - for (const alert of getRecoveredAlerts()) { - const recoveredAlertId = alert.getId(); - const alertUuid = getAlertUuid?.(recoveredAlertId) || undefined; + const recoveredAlerts = alertsClient.getRecoveredAlerts() ?? []; + for (const recoveredAlert of recoveredAlerts) { + const recoveredAlertId = recoveredAlert.alert.getId(); + const alertUuid = recoveredAlert.alert.getUuid(); - const state = alert.getState() as SyntheticsCommonState & SyntheticsMonitorStatusAlertState; + const state = recoveredAlert.alert.getState(); let recoveryReason = ''; let recoveryStatus = i18n.translate( @@ -279,7 +290,7 @@ export const setRecoveredAlertsContext = ({ } } - alert.setContext({ + const context = { ...state, ...(monitorSummary ? monitorSummary : {}), lastErrorMessage, @@ -290,7 +301,8 @@ export const setRecoveredAlertsContext = ({ ...(basePath && spaceId && alertUuid ? { [ALERT_DETAILS_URL]: getAlertDetailsUrl(basePath, spaceId, alertUuid) } : {}), - }); + }; + alertsClient.setAlertData({ id: recoveredAlertId, context }); } }; diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts index 2117e26e37cf71..f7a6b54ca19299 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts @@ -8,9 +8,16 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { isEmpty } from 'lodash'; import { ActionGroupIdsOf } from '@kbn/alerting-plugin/common'; -import { GetViewInAppRelativeUrlFnOpts } from '@kbn/alerting-plugin/server'; +import { PluginSetupContract } from '@kbn/alerting-plugin/server'; +import { + GetViewInAppRelativeUrlFnOpts, + AlertInstanceContext as AlertContext, + RuleExecutorOptions, + AlertsClientError, + IRuleTypeAlerts, +} from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; -import { createLifecycleRuleTypeFactory, IRuleDataClient } from '@kbn/rule-registry-plugin/server'; +import { ObservabilityUptimeAlert } from '@kbn/alerts-as-data-utils'; import { SyntheticsPluginsSetupDependencies, SyntheticsServerSetup } from '../../types'; import { DOWN_LABEL, getMonitorAlertDocument, getMonitorSummary } from './message_utils'; import { @@ -19,7 +26,7 @@ import { } from '../../../common/runtime_types/alert_rules/common'; import { OverviewStatus } from '../../../common/runtime_types'; import { StatusRuleExecutor } from './status_rule_executor'; -import { StatusRulePramsSchema } from '../../../common/rules/status_rule'; +import { StatusRulePramsSchema, StatusRuleParams } from '../../../common/rules/status_rule'; import { MONITOR_STATUS, SYNTHETICS_ALERT_RULE_TYPES, @@ -37,20 +44,26 @@ import { ALERT_DETAILS_URL, getActionVariables, VIEW_IN_APP_URL } from '../actio import { STATUS_RULE_NAME } from '../translations'; import { SyntheticsMonitorClient } from '../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; -export type ActionGroupIds = ActionGroupIdsOf; +type MonitorStatusRuleTypeParams = StatusRuleParams; +type MonitorStatusActionGroups = ActionGroupIdsOf; +type MonitorStatusRuleTypeState = SyntheticsCommonState; +type MonitorStatusAlertState = SyntheticsMonitorStatusAlertState; +type MonitorStatusAlertContext = AlertContext; +type MonitorStatusAlert = ObservabilityUptimeAlert; export const registerSyntheticsStatusCheckRule = ( server: SyntheticsServerSetup, plugins: SyntheticsPluginsSetupDependencies, syntheticsMonitorClient: SyntheticsMonitorClient, - ruleDataClient: IRuleDataClient + alerting: PluginSetupContract ) => { - const createLifecycleRuleType = createLifecycleRuleTypeFactory({ - ruleDataClient, - logger: server.logger, - }); + if (!alerting) { + throw new Error( + 'Cannot register the synthetics monitor status rule type. The alerting plugin needs to be enabled.' + ); + } - return createLifecycleRuleType({ + alerting.registerType({ id: SYNTHETICS_ALERT_RULE_TYPES.MONITOR_STATUS, category: DEFAULT_APP_CATEGORIES.observability.id, producer: 'uptime', @@ -64,19 +77,22 @@ export const registerSyntheticsStatusCheckRule = ( isExportable: true, minimumLicenseRequired: 'basic', doesSetRecoveryContext: true, - async executor({ state, params, services, spaceId, previousStartedAt }) { - const ruleState = state as SyntheticsCommonState; - + executor: async ( + options: RuleExecutorOptions< + MonitorStatusRuleTypeParams, + MonitorStatusRuleTypeState, + MonitorStatusAlertState, + MonitorStatusAlertContext, + MonitorStatusActionGroups, + MonitorStatusAlert + > + ) => { + const { state: ruleState, params, services, spaceId, previousStartedAt, startedAt } = options; + const { alertsClient, savedObjectsClient, scopedClusterClient, uiSettingsClient } = services; + if (!alertsClient) { + throw new AlertsClientError(); + } const { basePath } = server; - const { - alertFactory, - getAlertUuid, - savedObjectsClient, - scopedClusterClient, - alertWithLifecycle, - uiSettingsClient, - } = services; - const dateFormat = await uiSettingsClient.get('dateFormat'); const timezone = await uiSettingsClient.get('dateFormat:tz'); const tz = timezone === 'Browser' ? 'UTC' : timezone; @@ -106,13 +122,11 @@ export const registerSyntheticsStatusCheckRule = ( tz ); - const alert = alertWithLifecycle({ + const { uuid, start } = alertsClient.report({ id: alertId, - fields: getMonitorAlertDocument(monitorSummary), + actionGroup: MONITOR_STATUS.id, }); - const alertUuid = getAlertUuid(alertId); - const alertState = alert.getState() as SyntheticsMonitorStatusAlertState; - const errorStartedAt: string = alertState.errorStartedAt || ping['@timestamp']; + const errorStartedAt = start ?? startedAt.toISOString(); let relativeViewInAppUrl = ''; if (monitorSummary.stateId) { @@ -123,31 +137,29 @@ export const registerSyntheticsStatusCheckRule = ( }); } + const payload = getMonitorAlertDocument(monitorSummary); + const context = { ...monitorSummary, + idWithLocation, errorStartedAt, linkMessage: monitorSummary.stateId ? getFullViewInAppMessage(basePath, spaceId, relativeViewInAppUrl) : '', [VIEW_IN_APP_URL]: getViewInAppUrl(basePath, spaceId, relativeViewInAppUrl), + [ALERT_DETAILS_URL]: getAlertDetailsUrl(basePath, spaceId, uuid), }; - alert.replaceState({ - ...updateState(ruleState, true), - ...context, - idWithLocation, - }); - - alert.scheduleActions(MONITOR_STATUS.id, { - ...context, - [ALERT_DETAILS_URL]: getAlertDetailsUrl(basePath, spaceId, alertUuid), + alertsClient.setAlertData({ + id: alertId, + payload, + context, }); }); setRecoveredAlertsContext({ - alertFactory, + alertsClient, basePath, - getAlertUuid, spaceId, staleDownConfigs, upConfigs, @@ -159,7 +171,10 @@ export const registerSyntheticsStatusCheckRule = ( state: updateState(ruleState, !isEmpty(downConfigs), { downConfigs }), }; }, - alerts: UptimeRuleTypeAlertDefinition, + alerts: { + ...UptimeRuleTypeAlertDefinition, + shouldWrite: true, + } as IRuleTypeAlerts, getViewInAppRelativeUrl: ({ rule }: GetViewInAppRelativeUrlFnOpts<{}>) => observabilityPaths.ruleDetails(rule.id), }); diff --git a/x-pack/plugins/observability_solution/synthetics/server/server.ts b/x-pack/plugins/observability_solution/synthetics/server/server.ts index 69a1aa79d2410e..b394e4ffc68835 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/server.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/server.ts @@ -138,18 +138,9 @@ export const initSyntheticsServer = ( } }); - const { - alerting: { registerType }, - } = plugins; + const { alerting } = plugins; - const statusAlert = registerSyntheticsStatusCheckRule( - server, - plugins, - syntheticsMonitorClient, - ruleDataClient - ); - - registerType(statusAlert); + registerSyntheticsStatusCheckRule(server, plugins, syntheticsMonitorClient, alerting); const tlsRule = registerSyntheticsTLSCheckRule( server, @@ -158,5 +149,5 @@ export const initSyntheticsServer = ( ruleDataClient ); - registerType(tlsRule); + alerting.registerType(tlsRule); }; From 7e19cc566065962f5072f33506efeecdbaee14ec Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Thu, 20 Jun 2024 10:18:42 -0400 Subject: [PATCH 115/123] [Embeddables Rebuild] Clone panels with runtime state (#186052) Makes the clone operation use runtime state rather than serialized state. --- .../react_controls/control_renderer.tsx | 2 +- .../saved_book_react_embeddable.tsx | 11 +- .../react_embeddables/saved_book/types.ts | 2 +- .../interfaces/child_state.ts | 4 +- .../interfaces/serialized_state.ts | 4 +- .../presentation_publishing/index.ts | 18 +- .../interfaces/has_library_transforms.ts | 8 +- .../interfaces/titles/titles_api.ts | 8 + .../unlink_from_library_action.tsx | 2 +- .../api/duplicate_dashboard_panel.test.ts | 177 ---------- .../api/duplicate_dashboard_panel.test.tsx | 328 ++++++++++++++++++ .../api/duplicate_dashboard_panel.ts | 46 ++- .../create/create_dashboard.test.ts | 2 +- .../embeddable/create/create_dashboard.ts | 8 +- .../embeddable/dashboard_container.tsx | 12 +- .../dashboard_backup_service.ts | 2 +- .../react_embeddable_renderer.tsx | 4 +- .../react_embeddable_state.ts | 7 +- .../public/react_embeddable_system/types.ts | 2 +- .../kibana_utils/public/storage/storage.ts | 8 +- 20 files changed, 441 insertions(+), 214 deletions(-) delete mode 100644 src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.ts create mode 100644 src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.tsx diff --git a/examples/controls_example/public/react_controls/control_renderer.tsx b/examples/controls_example/public/react_controls/control_renderer.tsx index 471b12894bae79..1629673e64f7b0 100644 --- a/examples/controls_example/public/react_controls/control_renderer.tsx +++ b/examples/controls_example/public/react_controls/control_renderer.tsx @@ -59,7 +59,7 @@ export const ControlRenderer = < return fullApi; }; - const { rawState: initialState } = parentApi.getSerializedStateForChild(uuid); + const { rawState: initialState } = parentApi.getSerializedStateForChild(uuid) ?? {}; const { api, Component } = factory.buildControl( initialState as unknown as StateType, diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx index 0a9c3c4d7117b9..af96793e6522e5 100644 --- a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx @@ -35,7 +35,7 @@ import { const bookSerializedStateIsByReference = ( state?: BookSerializedState ): state is BookByReferenceSerializedState => { - return Boolean(state && (state as BookByReferenceSerializedState).savedBookId !== undefined); + return Boolean(state && (state as BookByReferenceSerializedState).savedBookId); }; export const getSavedBookEmbeddableFactory = (core: CoreStart) => { @@ -86,7 +86,7 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => { defaultMessage: 'book', }), serializeState: async () => { - if (savedBookId$.value === undefined) { + if (!Boolean(savedBookId$.value)) { // if this book is currently by value, we serialize the entire state. const bookByValueState: BookByValueSerializedState = { attributes: serializeBookAttributes(bookAttributesManager), @@ -97,7 +97,7 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => { // if this book is currently by reference, we serialize the reference and write to the external store. const bookByReferenceState: BookByReferenceSerializedState = { - savedBookId: savedBookId$.value, + savedBookId: savedBookId$.value!, ...serializeTitles(), }; @@ -123,6 +123,11 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => { unlinkFromLibrary: () => { savedBookId$.next(undefined); }, + getByValueRuntimeSnapshot: () => { + const snapshot = api.snapshotRuntimeState(); + delete snapshot.savedBookId; + return snapshot; + }, }, { savedBookId: [savedBookId$, (val) => savedBookId$.next(val)], diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts b/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts index 362d95604cf973..00290698a9b1df 100644 --- a/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts @@ -47,4 +47,4 @@ export interface BookRuntimeState export type BookApi = DefaultEmbeddableApi & HasEditCapabilities & - HasInPlaceLibraryTransforms; + HasInPlaceLibraryTransforms; diff --git a/packages/presentation/presentation_containers/interfaces/child_state.ts b/packages/presentation/presentation_containers/interfaces/child_state.ts index c197974c67add2..3a399d8a3c913a 100644 --- a/packages/presentation/presentation_containers/interfaces/child_state.ts +++ b/packages/presentation/presentation_containers/interfaces/child_state.ts @@ -9,7 +9,9 @@ import { SerializedPanelState } from './serialized_state'; export interface HasSerializedChildState { - getSerializedStateForChild: (childId: string) => SerializedPanelState; + getSerializedStateForChild: ( + childId: string + ) => SerializedPanelState | undefined; } export interface HasRuntimeChildState { diff --git a/packages/presentation/presentation_containers/interfaces/serialized_state.ts b/packages/presentation/presentation_containers/interfaces/serialized_state.ts index 593362ab6a7e14..be9e9d4236c33e 100644 --- a/packages/presentation/presentation_containers/interfaces/serialized_state.ts +++ b/packages/presentation/presentation_containers/interfaces/serialized_state.ts @@ -32,8 +32,8 @@ export const apiHasSerializableState = (api: unknown | null): api is HasSerializ export interface HasSnapshottableState { /** - * Serializes all runtime state exactly as it appears. This could be used - * to rehydrate a component's state without needing to deserialize it. + * Serializes all runtime state exactly as it appears. This can be used + * to rehydrate a component's state without needing to serialize then deserialize it. */ snapshotRuntimeState: () => RuntimeState; } diff --git a/packages/presentation/presentation_publishing/index.ts b/packages/presentation/presentation_publishing/index.ts index e3136215f3d40c..d56cd53b67a54d 100644 --- a/packages/presentation/presentation_publishing/index.ts +++ b/packages/presentation/presentation_publishing/index.ts @@ -16,8 +16,8 @@ export interface EmbeddableApiContext { export { getInitialValuesFromComparators, - runComparators, getUnchangingComparator, + runComparators, type ComparatorDefinition, type ComparatorFunction, type StateComparators, @@ -35,22 +35,22 @@ export { type SerializedTimeRange, } from './interfaces/fetch/initialize_time_range'; export { - apiPublishesPartialUnifiedSearch, apiPublishesFilters, + apiPublishesPartialUnifiedSearch, apiPublishesTimeRange, apiPublishesUnifiedSearch, apiPublishesWritableUnifiedSearch, useSearchApi, - type PublishesTimeRange, type PublishesFilters, + type PublishesTimeRange, + type PublishesTimeslice, type PublishesUnifiedSearch, type PublishesWritableUnifiedSearch, - type PublishesTimeslice, } from './interfaces/fetch/publishes_unified_search'; export { apiHasAppContext, - type HasAppContext, type EmbeddableAppContext, + type HasAppContext, } from './interfaces/has_app_context'; export { apiHasDisableTriggers, @@ -63,9 +63,9 @@ export { type HasExecutionContext, } from './interfaces/has_execution_context'; export { + apiHasInPlaceLibraryTransforms, apiHasLegacyLibraryTransforms, apiHasLibraryTransforms, - apiHasInPlaceLibraryTransforms, type HasInPlaceLibraryTransforms, type HasLegacyLibraryTransforms, type HasLibraryTransforms, @@ -130,7 +130,11 @@ export { type PublishesPanelTitle, type PublishesWritablePanelTitle, } from './interfaces/titles/publishes_panel_title'; -export { initializeTitles, type SerializedTitles } from './interfaces/titles/titles_api'; +export { + initializeTitles, + stateHasTitles, + type SerializedTitles, +} from './interfaces/titles/titles_api'; export { useBatchedOptionalPublishingSubjects, useBatchedPublishingSubjects, diff --git a/packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts b/packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts index 17d48eca51be7f..778748f0e1f2c4 100644 --- a/packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts +++ b/packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts @@ -34,7 +34,7 @@ interface LibraryTransformGuards { * APIs that inherit this interface can be linked to and unlinked from the library in place without * re-initialization. */ -export interface HasInPlaceLibraryTransforms +export interface HasInPlaceLibraryTransforms extends Partial, DuplicateTitleCheck { /** @@ -49,6 +49,11 @@ export interface HasInPlaceLibraryTransforms */ saveToLibrary: (title: string) => Promise; + /** + * gets a snapshot of this embeddable's runtime state without any state that links it to a library item. + */ + getByValueRuntimeSnapshot: () => RuntimeState; + /** * Un-links this embeddable from the library. This method is optional, and only needed if the Embeddable * is not meant to be re-initialized as part of the unlink operation. If the embeddable needs to be re-initialized @@ -69,6 +74,7 @@ export const apiHasInPlaceLibraryTransforms = ( }; /** + * @deprecated use HasInPlaceLibraryTransforms instead * APIs that inherit this interface can be linked to and unlinked from the library. After the save or unlink * operation, the embeddable will be reinitialized. */ diff --git a/packages/presentation/presentation_publishing/interfaces/titles/titles_api.ts b/packages/presentation/presentation_publishing/interfaces/titles/titles_api.ts index 026ceb1cc84fc8..772e7fe6b113a0 100644 --- a/packages/presentation/presentation_publishing/interfaces/titles/titles_api.ts +++ b/packages/presentation/presentation_publishing/interfaces/titles/titles_api.ts @@ -17,6 +17,14 @@ export interface SerializedTitles { hidePanelTitles?: boolean; } +export const stateHasTitles = (state: unknown): state is SerializedTitles => { + return ( + (state as SerializedTitles)?.title !== undefined || + (state as SerializedTitles)?.description !== undefined || + (state as SerializedTitles)?.hidePanelTitles !== undefined + ); +}; + export interface TitlesApi extends PublishesWritablePanelTitle, PublishesWritablePanelDescription {} export const initializeTitles = ( diff --git a/src/plugins/dashboard/public/dashboard_actions/unlink_from_library_action.tsx b/src/plugins/dashboard/public/dashboard_actions/unlink_from_library_action.tsx index 17612fa9c6ef75..77aa1e5036c7bf 100644 --- a/src/plugins/dashboard/public/dashboard_actions/unlink_from_library_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/unlink_from_library_action.tsx @@ -77,7 +77,7 @@ export class UnlinkFromLibraryAction implements Action { return api.canUnlinkFromLibrary(); } else if (apiHasInPlaceLibraryTransforms(api)) { const canUnLink = api.canUnlinkFromLibrary ? await api.canUnlinkFromLibrary() : true; - return canUnLink && api.libraryId$.value !== undefined; + return canUnLink && Boolean(api.libraryId$.value); } throw new IncompatibleActionError(); } diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.ts deleted file mode 100644 index 256d03681447db..00000000000000 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.ts +++ /dev/null @@ -1,177 +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 { CoreStart } from '@kbn/core/public'; -import { coreMock } from '@kbn/core/public/mocks'; -import { isErrorEmbeddable, ReferenceOrValueEmbeddable } from '@kbn/embeddable-plugin/public'; -import { - ContactCardEmbeddable, - ContactCardEmbeddableFactory, - ContactCardEmbeddableInput, - ContactCardEmbeddableOutput, - CONTACT_CARD_EMBEDDABLE, -} from '@kbn/embeddable-plugin/public/lib/test_samples/embeddables'; -import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; -import { duplicateDashboardPanel, incrementPanelTitle } from './duplicate_dashboard_panel'; -import { buildMockDashboard, getSampleDashboardPanel } from '../../../mocks'; -import { pluginServices } from '../../../services/plugin_services'; -import { DashboardContainer } from '../dashboard_container'; - -let container: DashboardContainer; -let genericEmbeddable: ContactCardEmbeddable; -let byRefOrValEmbeddable: ContactCardEmbeddable & ReferenceOrValueEmbeddable; -let coreStart: CoreStart; -beforeEach(async () => { - coreStart = coreMock.createStart(); - coreStart.savedObjects.client = { - ...coreStart.savedObjects.client, - get: jest.fn().mockImplementation(() => ({ attributes: { title: 'Holy moly' } })), - find: jest.fn().mockImplementation(() => ({ total: 15 })), - create: jest.fn().mockImplementation(() => ({ id: 'brandNewSavedObject' })), - }; - - const mockEmbeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); - - pluginServices.getServices().embeddable.getEmbeddableFactory = jest - .fn() - .mockReturnValue(mockEmbeddableFactory); - container = buildMockDashboard({ - overrides: { - panels: { - '123': getSampleDashboardPanel({ - explicitInput: { firstName: 'Kibanana', id: '123' }, - type: CONTACT_CARD_EMBEDDABLE, - }), - }, - }, - }); - - const refOrValContactCardEmbeddable = await container.addNewEmbeddable< - ContactCardEmbeddableInput, - ContactCardEmbeddableOutput, - ContactCardEmbeddable - >(CONTACT_CARD_EMBEDDABLE, { - firstName: 'RefOrValEmbeddable', - }); - - const nonRefOrValueContactCard = await container.addNewEmbeddable< - ContactCardEmbeddableInput, - ContactCardEmbeddableOutput, - ContactCardEmbeddable - >(CONTACT_CARD_EMBEDDABLE, { - firstName: 'Not a refOrValEmbeddable', - }); - - if ( - isErrorEmbeddable(refOrValContactCardEmbeddable) || - isErrorEmbeddable(nonRefOrValueContactCard) - ) { - throw new Error('Failed to create embeddables'); - } else { - genericEmbeddable = nonRefOrValueContactCard; - byRefOrValEmbeddable = embeddablePluginMock.mockRefOrValEmbeddable< - ContactCardEmbeddable, - ContactCardEmbeddableInput - >(refOrValContactCardEmbeddable, { - mockedByReferenceInput: { - savedObjectId: 'testSavedObjectId', - id: refOrValContactCardEmbeddable.id, - }, - mockedByValueInput: { firstName: 'RefOrValEmbeddable', id: refOrValContactCardEmbeddable.id }, - }); - jest.spyOn(byRefOrValEmbeddable, 'getInputAsValueType'); - } -}); - -test('Duplication adds a new embeddable', async () => { - const originalPanelCount = Object.keys(container.getInput().panels).length; - const originalPanelKeySet = new Set(Object.keys(container.getInput().panels)); - await duplicateDashboardPanel.bind(container)(byRefOrValEmbeddable.id); - - expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount + 1); - const newPanelId = Object.keys(container.getInput().panels).find( - (key) => !originalPanelKeySet.has(key) - ); - expect(newPanelId).toBeDefined(); - const newPanel = container.getInput().panels[newPanelId!]; - expect(newPanel.type).toEqual(byRefOrValEmbeddable.type); -}); - -test('Duplicates a RefOrVal embeddable by value', async () => { - const originalPanelKeySet = new Set(Object.keys(container.getInput().panels)); - await duplicateDashboardPanel.bind(container)(byRefOrValEmbeddable.id); - const newPanelId = Object.keys(container.getInput().panels).find( - (key) => !originalPanelKeySet.has(key) - ); - - const originalFirstName = ( - container.getInput().panels[byRefOrValEmbeddable.id].explicitInput as ContactCardEmbeddableInput - ).firstName; - - const newFirstName = ( - container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput - ).firstName; - - expect(byRefOrValEmbeddable.getInputAsValueType).toHaveBeenCalled(); - - expect(originalFirstName).toEqual(newFirstName); - expect(container.getInput().panels[newPanelId!].type).toEqual(byRefOrValEmbeddable.type); -}); - -test('Duplicates a non RefOrVal embeddable by value', async () => { - const originalPanelKeySet = new Set(Object.keys(container.getInput().panels)); - await duplicateDashboardPanel.bind(container)(genericEmbeddable.id); - const newPanelId = Object.keys(container.getInput().panels).find( - (key) => !originalPanelKeySet.has(key) - ); - - const originalFirstName = ( - container.getInput().panels[genericEmbeddable.id].explicitInput as ContactCardEmbeddableInput - ).firstName; - - const newFirstName = ( - container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput - ).firstName; - - expect(originalFirstName).toEqual(newFirstName); - expect(container.getInput().panels[newPanelId!].type).toEqual(genericEmbeddable.type); -}); - -test('Gets a unique title from the dashboard', async () => { - expect(await incrementPanelTitle(container, '')).toEqual(''); - - container.getPanelTitles = jest.fn().mockImplementation(() => { - return ['testDuplicateTitle', 'testDuplicateTitle (copy)', 'testUniqueTitle']; - }); - expect(await incrementPanelTitle(container, 'testUniqueTitle')).toEqual('testUniqueTitle (copy)'); - expect(await incrementPanelTitle(container, 'testDuplicateTitle')).toEqual( - 'testDuplicateTitle (copy 1)' - ); - - container.getPanelTitles = jest.fn().mockImplementation(() => { - return ['testDuplicateTitle', 'testDuplicateTitle (copy)'].concat( - Array.from([...Array(39)], (_, index) => `testDuplicateTitle (copy ${index + 1})`) - ); - }); - expect(await incrementPanelTitle(container, 'testDuplicateTitle')).toEqual( - 'testDuplicateTitle (copy 40)' - ); - expect(await incrementPanelTitle(container, 'testDuplicateTitle (copy 100)')).toEqual( - 'testDuplicateTitle (copy 40)' - ); - - container.getPanelTitles = jest.fn().mockImplementation(() => { - return ['testDuplicateTitle (copy 100)']; - }); - expect(await incrementPanelTitle(container, 'testDuplicateTitle')).toEqual( - 'testDuplicateTitle (copy 101)' - ); - expect(await incrementPanelTitle(container, 'testDuplicateTitle (copy 100)')).toEqual( - 'testDuplicateTitle (copy 101)' - ); -}); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.tsx new file mode 100644 index 00000000000000..39bb0f754cfbed --- /dev/null +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.test.tsx @@ -0,0 +1,328 @@ +/* + * 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 { CoreStart } from '@kbn/core/public'; +import { coreMock } from '@kbn/core/public/mocks'; +import { + isErrorEmbeddable, + ReactEmbeddableFactory, + ReferenceOrValueEmbeddable, +} from '@kbn/embeddable-plugin/public'; +import { + ContactCardEmbeddable, + ContactCardEmbeddableFactory, + ContactCardEmbeddableInput, + ContactCardEmbeddableOutput, + CONTACT_CARD_EMBEDDABLE, +} from '@kbn/embeddable-plugin/public/lib/test_samples/embeddables'; +import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; +import { + DefaultEmbeddableApi, + ReactEmbeddableRenderer, + registerReactEmbeddableFactory, +} from '@kbn/embeddable-plugin/public/react_embeddable_system'; +import { BuildReactEmbeddableApiRegistration } from '@kbn/embeddable-plugin/public/react_embeddable_system/types'; +import { HasSnapshottableState, SerializedPanelState } from '@kbn/presentation-containers'; +import { HasInPlaceLibraryTransforms, HasLibraryTransforms } from '@kbn/presentation-publishing'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { BehaviorSubject, lastValueFrom, Subject } from 'rxjs'; +import { buildMockDashboard, getSampleDashboardPanel } from '../../../mocks'; +import { pluginServices } from '../../../services/plugin_services'; +import { DashboardContainer } from '../dashboard_container'; +import { duplicateDashboardPanel, incrementPanelTitle } from './duplicate_dashboard_panel'; + +describe('Legacy embeddables', () => { + let container: DashboardContainer; + let genericEmbeddable: ContactCardEmbeddable; + let byRefOrValEmbeddable: ContactCardEmbeddable & ReferenceOrValueEmbeddable; + let coreStart: CoreStart; + beforeEach(async () => { + coreStart = coreMock.createStart(); + coreStart.savedObjects.client = { + ...coreStart.savedObjects.client, + get: jest.fn().mockImplementation(() => ({ attributes: { title: 'Holy moly' } })), + find: jest.fn().mockImplementation(() => ({ total: 15 })), + create: jest.fn().mockImplementation(() => ({ id: 'brandNewSavedObject' })), + }; + + const mockEmbeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); + + pluginServices.getServices().embeddable.getEmbeddableFactory = jest + .fn() + .mockReturnValue(mockEmbeddableFactory); + container = buildMockDashboard({ + overrides: { + panels: { + '123': getSampleDashboardPanel({ + explicitInput: { firstName: 'Kibanana', id: '123' }, + type: CONTACT_CARD_EMBEDDABLE, + }), + }, + }, + }); + + const refOrValContactCardEmbeddable = await container.addNewEmbeddable< + ContactCardEmbeddableInput, + ContactCardEmbeddableOutput, + ContactCardEmbeddable + >(CONTACT_CARD_EMBEDDABLE, { + firstName: 'RefOrValEmbeddable', + }); + + const nonRefOrValueContactCard = await container.addNewEmbeddable< + ContactCardEmbeddableInput, + ContactCardEmbeddableOutput, + ContactCardEmbeddable + >(CONTACT_CARD_EMBEDDABLE, { + firstName: 'Not a refOrValEmbeddable', + }); + + if ( + isErrorEmbeddable(refOrValContactCardEmbeddable) || + isErrorEmbeddable(nonRefOrValueContactCard) + ) { + throw new Error('Failed to create embeddables'); + } else { + genericEmbeddable = nonRefOrValueContactCard; + byRefOrValEmbeddable = embeddablePluginMock.mockRefOrValEmbeddable< + ContactCardEmbeddable, + ContactCardEmbeddableInput + >(refOrValContactCardEmbeddable, { + mockedByReferenceInput: { + savedObjectId: 'testSavedObjectId', + id: refOrValContactCardEmbeddable.id, + }, + mockedByValueInput: { + firstName: 'RefOrValEmbeddable', + id: refOrValContactCardEmbeddable.id, + }, + }); + jest.spyOn(byRefOrValEmbeddable, 'getInputAsValueType'); + } + }); + test('Duplication adds a new embeddable', async () => { + const originalPanelCount = Object.keys(container.getInput().panels).length; + const originalPanelKeySet = new Set(Object.keys(container.getInput().panels)); + await duplicateDashboardPanel.bind(container)(byRefOrValEmbeddable.id); + + expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount + 1); + const newPanelId = Object.keys(container.getInput().panels).find( + (key) => !originalPanelKeySet.has(key) + ); + expect(newPanelId).toBeDefined(); + const newPanel = container.getInput().panels[newPanelId!]; + expect(newPanel.type).toEqual(byRefOrValEmbeddable.type); + }); + + test('Duplicates a RefOrVal embeddable by value', async () => { + const originalPanelKeySet = new Set(Object.keys(container.getInput().panels)); + await duplicateDashboardPanel.bind(container)(byRefOrValEmbeddable.id); + const newPanelId = Object.keys(container.getInput().panels).find( + (key) => !originalPanelKeySet.has(key) + ); + + const originalFirstName = ( + container.getInput().panels[byRefOrValEmbeddable.id] + .explicitInput as ContactCardEmbeddableInput + ).firstName; + + const newFirstName = ( + container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput + ).firstName; + + expect(byRefOrValEmbeddable.getInputAsValueType).toHaveBeenCalled(); + + expect(originalFirstName).toEqual(newFirstName); + expect(container.getInput().panels[newPanelId!].type).toEqual(byRefOrValEmbeddable.type); + }); + + test('Duplicates a non RefOrVal embeddable by value', async () => { + const originalPanelKeySet = new Set(Object.keys(container.getInput().panels)); + await duplicateDashboardPanel.bind(container)(genericEmbeddable.id); + const newPanelId = Object.keys(container.getInput().panels).find( + (key) => !originalPanelKeySet.has(key) + ); + + const originalFirstName = ( + container.getInput().panels[genericEmbeddable.id].explicitInput as ContactCardEmbeddableInput + ).firstName; + + const newFirstName = ( + container.getInput().panels[newPanelId!].explicitInput as ContactCardEmbeddableInput + ).firstName; + + expect(originalFirstName).toEqual(newFirstName); + expect(container.getInput().panels[newPanelId!].type).toEqual(genericEmbeddable.type); + }); + + test('Gets a unique title from the dashboard', async () => { + expect(await incrementPanelTitle(container, '')).toEqual(''); + + container.getPanelTitles = jest.fn().mockImplementation(() => { + return ['testDuplicateTitle', 'testDuplicateTitle (copy)', 'testUniqueTitle']; + }); + expect(await incrementPanelTitle(container, 'testUniqueTitle')).toEqual( + 'testUniqueTitle (copy)' + ); + expect(await incrementPanelTitle(container, 'testDuplicateTitle')).toEqual( + 'testDuplicateTitle (copy 1)' + ); + + container.getPanelTitles = jest.fn().mockImplementation(() => { + return ['testDuplicateTitle', 'testDuplicateTitle (copy)'].concat( + Array.from([...Array(39)], (_, index) => `testDuplicateTitle (copy ${index + 1})`) + ); + }); + expect(await incrementPanelTitle(container, 'testDuplicateTitle')).toEqual( + 'testDuplicateTitle (copy 40)' + ); + expect(await incrementPanelTitle(container, 'testDuplicateTitle (copy 100)')).toEqual( + 'testDuplicateTitle (copy 40)' + ); + + container.getPanelTitles = jest.fn().mockImplementation(() => { + return ['testDuplicateTitle (copy 100)']; + }); + expect(await incrementPanelTitle(container, 'testDuplicateTitle')).toEqual( + 'testDuplicateTitle (copy 101)' + ); + expect(await incrementPanelTitle(container, 'testDuplicateTitle (copy 100)')).toEqual( + 'testDuplicateTitle (copy 101)' + ); + }); +}); + +describe('React embeddables', () => { + const testId = '1234'; + const buildDashboardWithReactEmbeddable = async ( + testType: string, + mockApi: BuildReactEmbeddableApiRegistration<{}, {}, Api> + ) => { + const fullApi$ = new Subject>(); + const reactEmbeddableFactory: ReactEmbeddableFactory<{}, {}, Api> = { + type: testType, + deserializeState: jest.fn().mockImplementation((state) => state.rawState), + buildEmbeddable: async (state, registerApi) => { + const fullApi = registerApi( + { + ...mockApi, + }, + {} + ); + fullApi$.next(fullApi); + fullApi$.complete(); + return { + Component: () =>
TEST DUPLICATE
, + api: fullApi, + }; + }, + }; + registerReactEmbeddableFactory(testType, async () => reactEmbeddableFactory); + const dashboard = buildMockDashboard({ + overrides: { + panels: { + [testId]: getSampleDashboardPanel({ + explicitInput: { id: testId }, + type: testType, + }), + }, + }, + }); + // render a fake Dashboard to initialize react embeddables + const FakeDashboard = () => { + return ( +
+ {Object.keys(dashboard.getInput().panels).map((panelId) => { + const panel = dashboard.getInput().panels[panelId]; + return ( +
+ dashboard.children$.next({ [panelId]: api })} + getParentApi={() => ({ + getSerializedStateForChild: () => + panel.explicitInput as unknown as SerializedPanelState | undefined, + })} + /> + + ); + })} + + ); + }; + render(); + + return { dashboard, apiPromise: lastValueFrom(fullApi$) }; + }; + + it('Duplicates child without library transforms', async () => { + const mockApi = { + serializeState: jest.fn().mockImplementation(() => ({ rawState: {} })), + }; + const { dashboard, apiPromise } = await buildDashboardWithReactEmbeddable( + 'byValueOnly', + mockApi + ); + const api = await apiPromise; + + const snapshotSpy = jest.spyOn(api, 'snapshotRuntimeState'); + + await duplicateDashboardPanel.bind(dashboard)(testId); + + expect(snapshotSpy).toHaveBeenCalled(); + expect(Object.keys(dashboard.getInput().panels).length).toBe(2); + }); + + it('Duplicates child with library transforms', async () => { + const libraryTransformsMockApi: BuildReactEmbeddableApiRegistration< + {}, + {}, + DefaultEmbeddableApi & HasLibraryTransforms + > = { + serializeState: jest.fn().mockImplementation(() => ({ rawState: {} })), + saveToLibrary: jest.fn(), + getByReferenceState: jest.fn(), + getByValueState: jest.fn(), + canLinkToLibrary: jest.fn(), + canUnlinkFromLibrary: jest.fn(), + checkForDuplicateTitle: jest.fn(), + }; + const { dashboard, apiPromise } = await buildDashboardWithReactEmbeddable( + 'libraryTransforms', + libraryTransformsMockApi + ); + await apiPromise; + + await duplicateDashboardPanel.bind(dashboard)(testId); + expect(libraryTransformsMockApi.getByValueState).toHaveBeenCalled(); + }); + + it('Duplicates a child with in place library transforms', async () => { + const inPlaceLibraryTransformsMockApi: BuildReactEmbeddableApiRegistration< + {}, + {}, + DefaultEmbeddableApi & HasInPlaceLibraryTransforms + > = { + unlinkFromLibrary: jest.fn(), + saveToLibrary: jest.fn(), + checkForDuplicateTitle: jest.fn(), + libraryId$: new BehaviorSubject(''), + getByValueRuntimeSnapshot: jest.fn(), + serializeState: jest.fn().mockImplementation(() => ({ rawState: {} })), + }; + const { dashboard, apiPromise } = await buildDashboardWithReactEmbeddable( + 'inPlaceLibraryTransforms', + inPlaceLibraryTransformsMockApi + ); + await apiPromise; + + await duplicateDashboardPanel.bind(dashboard)(testId); + expect(inPlaceLibraryTransformsMockApi.getByValueRuntimeSnapshot).toHaveBeenCalled(); + }); +}); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.ts index 225e89109639a3..e0840ad0912b3e 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/duplicate_dashboard_panel.ts @@ -7,7 +7,14 @@ */ import { isReferenceOrValueEmbeddable, PanelNotFoundError } from '@kbn/embeddable-plugin/public'; -import { apiPublishesPanelTitle, getPanelTitle } from '@kbn/presentation-publishing'; +import { apiHasSnapshottableState } from '@kbn/presentation-containers/interfaces/serialized_state'; +import { + apiHasInPlaceLibraryTransforms, + apiHasLibraryTransforms, + apiPublishesPanelTitle, + getPanelTitle, + stateHasTitles, +} from '@kbn/presentation-publishing'; import { filter, map, max } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; import { DashboardPanelState, prefixReferencesFromPanel } from '../../../../common'; @@ -52,18 +59,45 @@ const duplicateReactEmbeddableInput = async ( panelToClone: DashboardPanelState, idToDuplicate: string ) => { + const id = uuidv4(); const child = dashboard.children$.value[idToDuplicate]; const lastTitle = apiPublishesPanelTitle(child) ? getPanelTitle(child) ?? '' : ''; const newTitle = await incrementPanelTitle(dashboard, lastTitle); - const id = uuidv4(); - if (panelToClone.references) { - dashboard.savedObjectReferences.push(...prefixReferencesFromPanel(id, panelToClone.references)); + + /** + * For react embeddables that have library transforms, we need to ensure + * to clone them with serialized state and references. + * + * TODO: remove this section once all by reference capable react embeddables + * use in-place library transforms + */ + if (apiHasLibraryTransforms(child)) { + const byValueSerializedState = await child.getByValueState(); + if (panelToClone.references) { + dashboard.savedObjectReferences.push( + ...prefixReferencesFromPanel(id, panelToClone.references) + ); + } + return { + type: panelToClone.type, + explicitInput: { + ...byValueSerializedState, + title: newTitle, + id, + }, + }; } + + const runtimeSnapshot = (() => { + if (apiHasInPlaceLibraryTransforms(child)) return child.getByValueRuntimeSnapshot(); + return apiHasSnapshottableState(child) ? child.snapshotRuntimeState() : {}; + })(); + if (stateHasTitles(runtimeSnapshot)) runtimeSnapshot.title = newTitle; + + dashboard.setRuntimeStateForChild(id, runtimeSnapshot); return { type: panelToClone.type, explicitInput: { - ...panelToClone.explicitInput, - title: newTitle, id, }, }; diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts index f20e9f8c46c1bb..e3a321f2355df0 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts @@ -275,7 +275,7 @@ test('pulls panels from override input', async () => { // instead, the unsaved changes for React embeddables should be applied to the "restored runtime state" property of the Dashboard. expect( - (dashboard!.restoredRuntimeState!.someReactEmbeddablePanel as { title: string }).title + (dashboard!.getRuntimeStateForChild('someReactEmbeddablePanel') as { title: string }).title ).toEqual('an elegant override, from a more civilized age'); }); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts index 8f7e8bdb21bb57..32b21f0cf1c1ef 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts @@ -277,10 +277,14 @@ export const initializeDashboard = async ({ }; // -------------------------------------------------------------------------------------- - // Set latest runtime state for react embeddables. + // Set restored runtime state for react embeddables. // -------------------------------------------------------------------------------------- untilDashboardReady().then((dashboardContainer) => { - dashboardContainer.restoredRuntimeState = runtimePanelsToRestore; + for (const idWithRuntimeState of Object.keys(runtimePanelsToRestore)) { + const restoredRuntimeStateForChild = runtimePanelsToRestore[idWithRuntimeState]; + if (!restoredRuntimeStateForChild) continue; + dashboardContainer.setRuntimeStateForChild(idWithRuntimeState, restoredRuntimeStateForChild); + } }); // -------------------------------------------------------------------------------------- diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx index bb49255d41711f..1bfa289a5e9124 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx @@ -810,14 +810,22 @@ export class DashboardContainer public saveNotification$: Subject = new Subject(); public getSerializedStateForChild = (childId: string) => { + const rawState = this.getInput().panels[childId].explicitInput; + const { id, ...serializedState } = rawState; + if (!rawState || Object.keys(serializedState).length === 0) return; const references = getReferencesForPanelId(childId, this.savedObjectReferences); return { - rawState: this.getInput().panels[childId].explicitInput, + rawState, references, }; }; - public restoredRuntimeState: UnsavedPanelState | undefined = undefined; + private restoredRuntimeState: UnsavedPanelState | undefined = undefined; + public setRuntimeStateForChild = (childId: string, state: object) => { + const runtimeState = this.restoredRuntimeState ?? {}; + runtimeState[childId] = state; + this.restoredRuntimeState = runtimeState; + }; public getRuntimeStateForChild = (childId: string) => { return this.restoredRuntimeState?.[childId]; }; diff --git a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts b/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts index 5a121ef4304002..f97d88fd1c4fe7 100644 --- a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts +++ b/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts @@ -133,7 +133,7 @@ class DashboardBackupService implements DashboardBackupServiceType { const panelsStorage = this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY) ?? {}; set(panelsStorage, [this.activeSpaceId, id], unsavedPanels); - this.sessionStorage.set(DASHBOARD_PANELS_SESSION_KEY, panelsStorage); + this.sessionStorage.set(DASHBOARD_PANELS_SESSION_KEY, panelsStorage, true); } catch (e) { this.notifications.toasts.addDanger({ title: backupServiceStrings.getPanelsSetError(e.message), diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx index 002328cf222740..91f4e02527bbb1 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx @@ -9,6 +9,7 @@ import { apiIsPresentationContainer, HasSerializedChildState, + HasSnapshottableState, SerializedPanelState, } from '@kbn/presentation-containers'; import { PresentationPanel, PresentationPanelProps } from '@kbn/presentation-panel-plugin/public'; @@ -170,7 +171,7 @@ export const ReactEmbeddableRenderer = < } as unknown as SetReactEmbeddableApiRegistration); cleanupFunction.current = () => cleanup(); - return fullApi; + return fullApi as Api & HasSnapshottableState; }; const { api, Component } = await factory.buildEmbeddable( @@ -188,7 +189,6 @@ export const ReactEmbeddableRenderer = < } else { reportPhaseChange(false); } - return { api, Component }; }; diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts index ddfaf10953821c..f29d418bd39638 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts @@ -39,9 +39,10 @@ export const initializeReactEmbeddableState = async < factory: ReactEmbeddableFactory, parentApi: HasSerializedChildState ) => { - const lastSavedRuntimeState = await factory.deserializeState( - parentApi.getSerializedStateForChild(uuid) - ); + const serializedState = parentApi.getSerializedStateForChild(uuid); + const lastSavedRuntimeState = serializedState + ? await factory.deserializeState(serializedState) + : ({} as RuntimeState); // If the parent provides runtime state for the child (usually as a state backup or cache), // we merge it with the last saved runtime state. diff --git a/src/plugins/embeddable/public/react_embeddable_system/types.ts b/src/plugins/embeddable/public/react_embeddable_system/types.ts index cc4b9cf9b7976f..e9a5a697f07e5b 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/types.ts +++ b/src/plugins/embeddable/public/react_embeddable_system/types.ts @@ -114,7 +114,7 @@ export interface ReactEmbeddableFactory< buildApi: ( apiRegistration: BuildReactEmbeddableApiRegistration, comparators: StateComparators - ) => Api, + ) => Api & HasSnapshottableState, uuid: string, parentApi: unknown | undefined, /** `setApi` should be used when the unsaved changes logic in `buildApi` is unnecessary */ diff --git a/src/plugins/kibana_utils/public/storage/storage.ts b/src/plugins/kibana_utils/public/storage/storage.ts index 7f759c005daad7..497fdef49abc0d 100644 --- a/src/plugins/kibana_utils/public/storage/storage.ts +++ b/src/plugins/kibana_utils/public/storage/storage.ts @@ -32,9 +32,13 @@ export class Storage implements IStorageWrapper { } }; - public set = (key: string, value: any) => { + public set = (key: string, value: any, includeUndefined: boolean = false) => { + const replacer = includeUndefined + ? (_: string, currentValue: any) => + typeof currentValue === 'undefined' ? null : currentValue + : undefined; try { - return this.store.setItem(key, JSON.stringify(value)); + return this.store.setItem(key, JSON.stringify(value, replacer)); } catch (e) { return false; } From 6ce61db2ff8bad6405d94a177a64f5c336ea5813 Mon Sep 17 00:00:00 2001 From: dkirchan <55240027+dkirchan@users.noreply.github.com> Date: Thu, 20 Jun 2024 17:30:35 +0300 Subject: [PATCH 116/123] [Security][Serverless] Add Product types in FTR API Integration tests. (#184309) # Pull Request Overview This pull request (PR): 1. Enables Product Types for FTR API Integration Test Suites in Serverless MKI: - Previously, the test suites ignored product types entirely. With this PR, scripts to run the tests have been relocated to x-pack/test/security_solution_api_integration/scripts. - Users can now run tests from the API Integration tests directory for security solutions by using the command: TARGET_SCRIPT={script_from_package_json} node ./scripts/mki_start_api_ftr_execution. This will execute the following steps: 1. Create a security serverless project, respecting the product types specified in the serverless configuration found in the config folder of the relevant test suite. 2. Reset credentials. 3. Wait for Elasticsearch (ES) and Kibana to be ready and available. 4. Execute the tests. 5. Delete the project upon completion. 2. Adds Proxy Services Organizations to .ftr Role Users Files: - This PR updates the .ftr role_users files to include all proxy services organizations, ensuring they have the necessary permissions for the tests. # Implementation Details Product Types - Previous Setup: - A project was created and handed over to the test suite to run the API tests against, without considering product types. - Changes Introduced: - The script execution for tests has moved to x-pack/test/security_solution_api_integration/scripts. - Tests can be initiated using the command from the API Integration tests folder where package.json exists: ``` TARGET_SCRIPT={script_from_package_json} node ./scripts/mki_start_api_ftr_execution ``` - The mki_start_api_ftr_execution script performs several steps to run the tests, including creating a security serverless project with specified product types, resetting credentials, ensuring ES and Kibana readiness, executing tests, and cleaning up the project afterward. - The script reads extra configuration (currently only product types are supported) in the specific format as is, from the following file : [api_configs.json](https://github.com/elastic/kibana/pull/184309/files#diff-1122baffe7ff843b1f486cee95468bed5851a9a4934be747f540bd42dc9a07daR2). The key for the JSON file is the name of the script in [package.json](https://github.com/elastic/kibana/pull/184309/files#diff-c6af1c81947b3a77bed431c688c7ad38c8969bd52e1c3ea92d643f09d422eb61R296) - If a specific configuration is not required and the default complete project is needed for the test to run, the key and configuration in the `api_configs.json` file can be ommitted. # Summary This PR enhances the flexibility and functionality of the FTR API integration test suites for serverless MKI by incorporating product type considerations and updating the role_users configuration to include proxy services organizations. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../api_integration/api-integration-tests.sh | 6 +- .../start_api_ftr_execution.js | 10 - .../prepare_vault_entries.sh | 7 + .../README.md | 7 + .../package.json | 12 +- .../scripts/api_configs.json | 198 ++++++++++++++++++ .../scripts/mki_api_ftr_execution.ts | 55 +++-- .../scripts/mki_start_api_ftr_execution.js | 9 + .../tsconfig.json | 1 + 9 files changed, 272 insertions(+), 33 deletions(-) delete mode 100644 .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/start_api_ftr_execution.js create mode 100644 x-pack/test/security_solution_api_integration/scripts/api_configs.json rename .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api_ftr_execution.ts => x-pack/test/security_solution_api_integration/scripts/mki_api_ftr_execution.ts (77%) create mode 100644 x-pack/test/security_solution_api_integration/scripts/mki_start_api_ftr_execution.js diff --git a/.buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh b/.buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh index 23231465932dda..1aede759481a5c 100755 --- a/.buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh +++ b/.buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh @@ -15,7 +15,11 @@ buildkite-agent meta-data set "${BUILDKITE_JOB_ID}_is_test_execution_step" "true source .buildkite/scripts/pipelines/security_solution_quality_gate/prepare_vault_entries.sh echo "--- Running test script $1" -TARGET_SCRIPT=$1 node .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/start_api_ftr_execution + +cd x-pack/test/security_solution_api_integration +set +e + +TARGET_SCRIPT=$1 node ./scripts/mki_start_api_ftr_execution cmd_status=$? echo "Exit code with status: $cmd_status" exit $cmd_status diff --git a/.buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/start_api_ftr_execution.js b/.buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/start_api_ftr_execution.js deleted file mode 100644 index 2ee5715a0fe2b8..00000000000000 --- a/.buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/start_api_ftr_execution.js +++ /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 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. - */ - -require('../../../../../src/setup_node_env'); -require('./api_ftr_execution').cli(); diff --git a/.buildkite/scripts/pipelines/security_solution_quality_gate/prepare_vault_entries.sh b/.buildkite/scripts/pipelines/security_solution_quality_gate/prepare_vault_entries.sh index a7f1529e1fb9b6..5c21851e7585fb 100644 --- a/.buildkite/scripts/pipelines/security_solution_quality_gate/prepare_vault_entries.sh +++ b/.buildkite/scripts/pipelines/security_solution_quality_gate/prepare_vault_entries.sh @@ -8,6 +8,13 @@ vault_get security-quality-gate/role-users data -format=json > .ftr/role_users.j vault_get security-quality-gate/role-users/sec-sol-auto-01 data -format=json > .ftr/sec-sol-auto-01.json vault_get security-quality-gate/role-users/sec-sol-auto-02 data -format=json > .ftr/sec-sol-auto-02.json vault_get security-quality-gate/role-users/sec-sol-auto-03 data -format=json > .ftr/sec-sol-auto-03.json +vault_get security-quality-gate/role-users/sec-sol-auto-04 data -format=json > .ftr/sec-sol-auto-04.json +vault_get security-quality-gate/role-users/sec-sol-auto-05 data -format=json > .ftr/sec-sol-auto-05.json +vault_get security-quality-gate/role-users/sec-sol-auto-06 data -format=json > .ftr/sec-sol-auto-06.json +vault_get security-quality-gate/role-users/sec-sol-auto-07 data -format=json > .ftr/sec-sol-auto-07.json +vault_get security-quality-gate/role-users/sec-sol-auto-08 data -format=json > .ftr/sec-sol-auto-08.json +vault_get security-quality-gate/role-users/sec-sol-auto-09 data -format=json > .ftr/sec-sol-auto-09.json +vault_get security-quality-gate/role-users/sec-sol-auto-10 data -format=json > .ftr/sec-sol-auto-10.json # The vault entries relevant to QA Cloud export CLOUD_QA_API_KEY=$(vault_get security-solution-quality-gate qa_api_key) diff --git a/x-pack/test/security_solution_api_integration/README.md b/x-pack/test/security_solution_api_integration/README.md index 1cfc87a1420c96..eeb0682c1358e9 100644 --- a/x-pack/test/security_solution_api_integration/README.md +++ b/x-pack/test/security_solution_api_integration/README.md @@ -47,6 +47,13 @@ ex: 3. In these new configuration files, include references to the base configurations located under the config directory to inherit CI configurations, environment variables, and other settings. 4. Append a new entry in the `ftr_configs.yml` file to enable the execution of the newly added tests within the CI pipeline. +## Adding tests for MKI which rely onto NON default project configuration + +The default project type configuration in Serverless is complete. If for the needs of a test suite a different configuration is required, e.g. [PLI - Essentials](https://github.com/elastic/kibana/blob/36578e82fa0a0440c1657a0ca688106c895d5e4e/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/basic_license_essentials_tier/configs/serverless.config.ts#L13), the already mentioned configuration in the permalink **does not work** for MKI. The override is needed to be added in the `./scripts/api_configs.json` file under the key with exact same name as the one of the script in `package.json` file which is running. + +There are already configurations in the `./scripts/api_configs.json` which you can follow in order to add yours when it is needed. The currently supported configuration, allows **ONLY** the PLIs to be configured. Thus, experimental feature flags **are not yet supported** and the test should be skipped until further notice. + +**NOTE**: If a target script living in `package.json` file, does not require any further configuration, then the entry in `./scripts/api_configs.json` file, **can be omitted!** # Testing locally diff --git a/x-pack/test/security_solution_api_integration/package.json b/x-pack/test/security_solution_api_integration/package.json index acc78fba0fddff..52ff9a233b4774 100644 --- a/x-pack/test/security_solution_api_integration/package.json +++ b/x-pack/test/security_solution_api_integration/package.json @@ -297,11 +297,11 @@ "rule_read:basic:server:ess": "npm run initialize-server:rm:basic_essentials rule_read ess", "rule_read:basic:runner:ess": "npm run run-tests:rm:basic_essentials rule_read ess essEnv", - "rules_management:essentials:server:serverless": "npm run initialize-server:rm:basic_essentials rule_management serverless", - "rules_management:essentials:runner:serverless": "npm run run-tests:rm:basic_essentials rule_management serverless serverlessEnv", - "rules_management:essentials:qa:serverless": "npm run run-tests:rm:basic_essentials rule_management serverless qaPeriodicEnv", - "rules_management:essentials:qa:serverless:release": "npm run run-tests:rm:basic_essentials rule_management serverless qaEnv", - "rules_management:basic:server:ess": "npm run initialize-server:rm:basic_essentials rule_management ess", - "rules_management:basic:runner:ess": "npm run run-tests:rm:basic_essentials rule_management ess essEnv" + "rules_management:essentials:server:serverless": "npm run initialize-server:rm:basic_essentials rule_management serverless", + "rules_management:essentials:runner:serverless": "npm run run-tests:rm:basic_essentials rule_management serverless serverlessEnv", + "rules_management:essentials:qa:serverless": "npm run run-tests:rm:basic_essentials rule_management serverless qaPeriodicEnv", + "rules_management:essentials:qa:serverless:release": "npm run run-tests:rm:basic_essentials rule_management serverless qaEnv", + "rules_management:basic:server:ess": "npm run initialize-server:rm:basic_essentials rule_management ess", + "rules_management:basic:runner:ess": "npm run run-tests:rm:basic_essentials rule_management ess essEnv" } } diff --git a/x-pack/test/security_solution_api_integration/scripts/api_configs.json b/x-pack/test/security_solution_api_integration/scripts/api_configs.json new file mode 100644 index 00000000000000..6a25037ccb9050 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/scripts/api_configs.json @@ -0,0 +1,198 @@ +{ + "nlp_cleanup_task:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" }, + { "product_line": "cloud", "product_tier": "essentials" } + ] + }, + "nlp_cleanup_task:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" }, + { "product_line": "cloud", "product_tier": "essentials" } + ] + }, + "entity_analytics:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" }, + { "product_line": "cloud", "product_tier": "essentials" } + ] + }, + "entity_analytics:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" }, + { "product_line": "cloud", "product_tier": "essentials" } + ] + }, + "exception_workflows:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_workflows:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_date_numeric_types:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_date_numeric_types:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_keyword:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_keyword:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_ips:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_ips:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_long:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_long:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_text:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "exception_operators_text:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "alerts:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "alerts:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_creation:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_creation:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_update:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_update:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_patch:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_patch:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_delete:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_delete:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_import_export:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_import_export:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rules_management:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rules_management:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_read:essentials:qa:serverless": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + }, + "rule_read:essentials:qa:serverless:release": { + "productTypes": [ + { "product_line": "security", "product_tier": "essentials" }, + { "product_line": "endpoint", "product_tier": "essentials" } + ] + } +} diff --git a/.buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api_ftr_execution.ts b/x-pack/test/security_solution_api_integration/scripts/mki_api_ftr_execution.ts similarity index 77% rename from .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api_ftr_execution.ts rename to x-pack/test/security_solution_api_integration/scripts/mki_api_ftr_execution.ts index f1e957873de0a3..3dff7e2c1d0714 100644 --- a/.buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api_ftr_execution.ts +++ b/x-pack/test/security_solution_api_integration/scripts/mki_api_ftr_execution.ts @@ -1,17 +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 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. + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import { run } from '@kbn/dev-cli-runner'; import { ToolingLog } from '@kbn/tooling-log'; import { exec } from 'child_process'; import crypto from 'crypto'; - -import type { ProjectHandler } from '@kbn/security-solution-plugin/scripts/run_cypress/project_handler/project_handler'; +import fs from 'fs'; +import type { + ProductType, + ProjectHandler, +} from '@kbn/security-solution-plugin/scripts/run_cypress/project_handler/project_handler'; import { CloudHandler } from '@kbn/security-solution-plugin/scripts/run_cypress/project_handler/cloud_project_handler'; import { ProxyHandler } from '@kbn/security-solution-plugin/scripts/run_cypress/project_handler/proxy_project_handler'; import { @@ -25,28 +27,33 @@ const BASE_ENV_URL = `${process.env.QA_CONSOLE_URL}`; const PROJECT_NAME_PREFIX = 'kibana-ftr-api-integration-security-solution'; // Function to execute a command and return a Promise with the status code -function executeCommand(command: string, envVars: any, workDir: string): Promise { +function executeCommand( + command: string, + envVars: any, + log: ToolingLog, + workDir?: string +): Promise { return new Promise((resolve, reject) => { - const childProcess = exec(command, { env: envVars, cwd: workDir }, (error, stdout, stderr) => { + const childProcess = exec(command, { env: envVars }, (error, stdout, stderr) => { if (error) { - console.error(`exec error: ${error}`); + log.error(`exec error: ${error}`); process.exitCode = error.code; } }); // Listen and print stdout data childProcess.stdout?.on('data', (data) => { - console.log(data); + log.info(data); }); // Listen and print stderr data childProcess.stderr?.on('data', (data) => { - console.log(data); + log.info(data); }); // Listen for process exit childProcess.on('exit', (code) => { - console.log(`Node process for target ${process.env.TARGET_SCRIPT} exits with code : ${code}`); + log.info(`Node process for target ${process.env.TARGET_SCRIPT} exits with code : ${code}`); if (code !== 0) { reject(code); return; @@ -56,6 +63,24 @@ function executeCommand(command: string, envVars: any, workDir: string): Promise }); } +async function parseProductTypes(log: ToolingLog): Promise { + if (!process.env.TARGET_SCRIPT) { + log.error('TARGET_SCRIPT environment variable is not provided. Aborting...'); + return process.exit(1); + } + + const apiConfigs = JSON.parse(await fs.promises.readFile('./scripts/api_configs.json', 'utf8')); + try { + const productTypes: ProductType[] = apiConfigs[process.env.TARGET_SCRIPT] + .productTypes as ProductType[]; + return productTypes && productTypes.length > 0 ? productTypes : undefined; + } catch (err) { + // If the configuration for the script is not needed, it can be omitted from the json file. + log.warning(`Extended configuration was not found for script : ${process.env.TARGET_SCRIPT}`); + return undefined; + } +} + export const cli = () => { run( async (context) => { @@ -89,14 +114,13 @@ export const cli = () => { const id = crypto.randomBytes(8).toString('hex'); const PROJECT_NAME = `${PROJECT_NAME_PREFIX}-${id}`; + const productTypes = await parseProductTypes(log); // Creating project for the test to run - const project = await cloudHandler.createSecurityProject(PROJECT_NAME); - log.info(project); + const project = await cloudHandler.createSecurityProject(PROJECT_NAME, productTypes); if (!project) { log.error('Failed to create project.'); - return process.exit(1); } let statusCode: number = 0; @@ -132,7 +156,6 @@ export const cli = () => { const testCloud = 1; const testEsUrl = `https://${credentials.username}:${credentials.password}@${FORMATTED_ES_URL}`; const testKibanaUrl = `https://${credentials.username}:${credentials.password}@${FORMATTED_KB_URL}`; - const workDir = 'x-pack/test/security_solution_api_integration'; const envVars = { ...process.env, TEST_CLOUD: testCloud.toString(), @@ -140,7 +163,7 @@ export const cli = () => { TEST_KIBANA_URL: testKibanaUrl, }; - statusCode = await executeCommand(command, envVars, workDir); + statusCode = await executeCommand(command, envVars, log); } catch (err) { log.error('An error occured when running the test script.'); log.error(err.message); diff --git a/x-pack/test/security_solution_api_integration/scripts/mki_start_api_ftr_execution.js b/x-pack/test/security_solution_api_integration/scripts/mki_start_api_ftr_execution.js new file mode 100644 index 00000000000000..587ce8e13f0b6d --- /dev/null +++ b/x-pack/test/security_solution_api_integration/scripts/mki_start_api_ftr_execution.js @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +require('../../../../src/setup_node_env'); +require('./mki_api_ftr_execution').cli(); diff --git a/x-pack/test/security_solution_api_integration/tsconfig.json b/x-pack/test/security_solution_api_integration/tsconfig.json index 269822e345de8a..c9bcdf8ccde2b6 100644 --- a/x-pack/test/security_solution_api_integration/tsconfig.json +++ b/x-pack/test/security_solution_api_integration/tsconfig.json @@ -47,5 +47,6 @@ "@kbn/timelines-plugin", "@kbn/ftr-common-functional-ui-services", "@kbn/test-subj-selector", + "@kbn/dev-cli-runner", ] } From 153ec668e388129971605d3c875a2969221533de Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Thu, 20 Jun 2024 09:34:17 -0500 Subject: [PATCH 117/123] [Security Solution][Notes] - store setup (#186433) --- .github/CODEOWNERS | 1 + .../public/common/mock/global_state.ts | 23 +++++ .../public/common/store/reducer.test.tsx | 8 +- .../public/common/store/reducer.ts | 7 +- .../public/common/store/store.ts | 8 +- .../public/common/store/types.ts | 4 +- .../left/components/notes_details.tsx | 12 ++- .../security_solution/public/notes/api/api.ts | 33 +++++++ .../public/notes/store/normalize.ts | 54 ++++++++++++ .../public/notes/store/notes.slice.ts | 86 +++++++++++++++++++ 10 files changed, 228 insertions(+), 8 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/notes/api/api.ts create mode 100644 x-pack/plugins/security_solution/public/notes/store/normalize.ts create mode 100644 x-pack/plugins/security_solution/public/notes/store/notes.slice.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e06b53da0ab57e..a6a45a24266a8f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1445,6 +1445,7 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/detections/components/alerts_info @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/flyout/document_details @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/flyout/shared @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/notes @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/resolver @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/threat_intelligence @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/timelines @elastic/security-threat-hunting-investigations diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index b99e788246dce5..7a77de9d235553 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -7,6 +7,7 @@ import { TableId } from '@kbn/securitysolution-data-table'; import type { DataViewSpec, FieldSpec } from '@kbn/data-views-plugin/public'; +import { ReqStatus } from '../../notes/store/notes.slice'; import { HostsFields } from '../../../common/api/search_strategy/hosts/model/sort'; import { InputsModelId } from '../store/inputs/constants'; import { @@ -500,4 +501,26 @@ export const mockGlobalState: State = { */ management: mockManagementState as ManagementState, discover: getMockDiscoverInTimelineState(), + notes: { + ids: ['1'], + entities: { + '1': { + eventId: 'event-id', + noteId: '1', + note: 'note-1', + timelineId: 'timeline-1', + created: 1663882629000, + createdBy: 'elastic', + updated: 1663882629000, + updatedBy: 'elastic', + version: 'version', + }, + }, + status: { + fetchNotesByDocumentId: ReqStatus.Idle, + }, + error: { + fetchNotesByDocumentId: null, + }, + }, }; diff --git a/x-pack/plugins/security_solution/public/common/store/reducer.test.tsx b/x-pack/plugins/security_solution/public/common/store/reducer.test.tsx index 0710872ae547d6..b5b6cd687205a2 100644 --- a/x-pack/plugins/security_solution/public/common/store/reducer.test.tsx +++ b/x-pack/plugins/security_solution/public/common/store/reducer.test.tsx @@ -13,6 +13,7 @@ import { useSourcererDataView } from '../../sourcerer/containers'; import { renderHook } from '@testing-library/react-hooks'; import { initialGroupingState } from './grouping/reducer'; import { initialAnalyzerState } from '../../resolver/store/helpers'; +import { initialNotesState } from '../../notes/store/notes.slice'; jest.mock('../hooks/use_selector'); jest.mock('../lib/kibana', () => { @@ -69,7 +70,8 @@ describe('createInitialState', () => { }, { analyzer: initialAnalyzerState, - } + }, + initialNotesState ); test('indicesExist should be TRUE if patternList is NOT empty', async () => { @@ -107,7 +109,9 @@ describe('createInitialState', () => { }, { analyzer: initialAnalyzerState, - } + }, + + initialNotesState ); const { result } = renderHook(() => useSourcererDataView(), { wrapper: ({ children }) => ( diff --git a/x-pack/plugins/security_solution/public/common/store/reducer.ts b/x-pack/plugins/security_solution/public/common/store/reducer.ts index 5ec7ae66bb2bd5..ea684909a87763 100644 --- a/x-pack/plugins/security_solution/public/common/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/common/store/reducer.ts @@ -35,6 +35,8 @@ import type { GroupState } from './grouping/types'; import { analyzerReducer } from '../../resolver/store/reducer'; import { securitySolutionDiscoverReducer } from './discover/reducer'; import type { AnalyzerState } from '../../resolver/types'; +import type { NotesState } from '../../notes/store/notes.slice'; +import { notesReducer } from '../../notes/store/notes.slice'; enableMapSet(); @@ -66,7 +68,8 @@ export const createInitialState = ( }, dataTableState: DataTableState, groupsState: GroupState, - analyzerState: AnalyzerState + analyzerState: AnalyzerState, + notesState: NotesState ): State => { const initialPatterns = { [SourcererScopeName.default]: getScopePatternListSelection( @@ -128,6 +131,7 @@ export const createInitialState = ( internal: undefined, savedSearch: undefined, }, + notes: notesState, }; return preloadedState; @@ -150,4 +154,5 @@ export const createReducer: ( analyzer: analyzerReducer, discover: securitySolutionDiscoverReducer, ...pluginsReducer, + notes: notesReducer, }); diff --git a/x-pack/plugins/security_solution/public/common/store/store.ts b/x-pack/plugins/security_solution/public/common/store/store.ts index 5b3500a58d9c62..34209fae78bcf1 100644 --- a/x-pack/plugins/security_solution/public/common/store/store.ts +++ b/x-pack/plugins/security_solution/public/common/store/store.ts @@ -5,6 +5,7 @@ * 2.0. */ +import thunk from 'redux-thunk'; import type { Action, Store, @@ -54,6 +55,7 @@ import { dataAccessLayerFactory } from '../../resolver/data_access_layer/factory import { sourcererActions } from '../../sourcerer/store'; import { createMiddlewares } from './middlewares'; import { addNewTimeline } from '../../timelines/store/helpers'; +import { initialNotesState } from '../../notes/store/notes.slice'; let store: Store | null = null; @@ -168,7 +170,8 @@ export const createStoreFactory = async ( }, dataTableInitialState, groupsInitialState, - analyzerInitialState + analyzerInitialState, + initialNotesState ); const rootReducer = { @@ -284,7 +287,8 @@ export const createStore = ( const middlewareEnhancer = applyMiddleware( ...createMiddlewares(kibana, storage), telemetryMiddleware, - ...(additionalMiddleware ?? []) + ...(additionalMiddleware ?? []), + thunk ); store = createReduxStore( diff --git a/x-pack/plugins/security_solution/public/common/store/types.ts b/x-pack/plugins/security_solution/public/common/store/types.ts index 3623ec8837ad49..bf83f9146bdb22 100644 --- a/x-pack/plugins/security_solution/public/common/store/types.ts +++ b/x-pack/plugins/security_solution/public/common/store/types.ts @@ -25,11 +25,11 @@ import type { GlobalUrlParam } from './global_url_param'; import type { GroupState } from './grouping/types'; import type { SecuritySolutionDiscoverState } from './discover/model'; import type { AnalyzerState } from '../../resolver/types'; +import type { NotesState } from '../../notes/store/notes.slice'; export type State = HostsPluginState & UsersPluginState & NetworkPluginState & - UsersPluginState & TimelinePluginState & ManagementPluginState & { app: AppState; @@ -40,7 +40,7 @@ export type State = HostsPluginState & discover: SecuritySolutionDiscoverState; } & DataTableState & GroupState & - AnalyzerState; + AnalyzerState & { notes: NotesState }; /** * The Redux store type for the Security app. */ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/notes_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/notes_details.tsx index 3c23ab55cff0f1..7d7d370d4953c2 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/notes_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/notes_details.tsx @@ -5,13 +5,23 @@ * 2.0. */ -import React, { memo } from 'react'; +import React, { memo, useEffect } from 'react'; +import { useDispatch } from 'react-redux'; +import { fetchNotesByDocumentId } from '../../../../notes/store/notes.slice'; +import { useLeftPanelContext } from '../context'; /** * List all the notes for a document id and allows to create new notes associated with that document. * Displayed in the document details expandable flyout left section. */ export const NotesDetails = memo(() => { + const dispatch = useDispatch(); + const { eventId } = useLeftPanelContext(); + + useEffect(() => { + dispatch(fetchNotesByDocumentId({ documentId: eventId })); + }, [dispatch, eventId]); + return <>; }); diff --git a/x-pack/plugins/security_solution/public/notes/api/api.ts b/x-pack/plugins/security_solution/public/notes/api/api.ts new file mode 100644 index 00000000000000..d9cef8cf997abd --- /dev/null +++ b/x-pack/plugins/security_solution/public/notes/api/api.ts @@ -0,0 +1,33 @@ +/* + * 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 * as uuid from 'uuid'; + +// TODO point to the correct API when it is available +/** + * Fetches all the notes for a document id + */ +export const fetchNotesByDocumentId = async (documentId: string) => { + const response = { + totalCount: 1, + notes: [generateNoteMock(documentId)], + }; + return response.notes; +}; + +// TODO remove when the API is available +const generateNoteMock = (documentId: string) => ({ + noteId: uuid.v4(), + version: 'WzU1MDEsMV0=', + timelineId: '', + eventId: documentId, + note: 'This is a mocked note', + created: new Date().getTime(), + createdBy: 'elastic', + updated: new Date().getTime(), + updatedBy: 'elastic', +}); diff --git a/x-pack/plugins/security_solution/public/notes/store/normalize.ts b/x-pack/plugins/security_solution/public/notes/store/normalize.ts new file mode 100644 index 00000000000000..2b433a35d7c86b --- /dev/null +++ b/x-pack/plugins/security_solution/public/notes/store/normalize.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Note } from '../../../common/api/timeline'; + +/** + * Interface to represent a normalized entity + */ +export interface NormalizedEntity { + entities: { + [entity: string]: { + [id: string]: T; + }; + }; + result: string; +} + +/** + * Interface to represent normalized entities + */ +export interface NormalizedEntities { + entities: { + [entity: string]: { + [id: string]: T; + }; + }; + result: string[]; +} + +/** + * Normalizes a single note + */ +export const normalizeEntity = (res: Note): NormalizedEntity => ({ + entities: { + notes: { + [res.noteId]: res, + }, + }, + result: res.noteId, +}); + +/** + * Normalizes an array of notes + */ +export const normalizeEntities = (res: Note[]): NormalizedEntities => ({ + entities: { + notes: res.reduce((obj, item) => Object.assign(obj, { [item.noteId]: item }), {}), + }, + result: res.map((note) => note.noteId), +}); diff --git a/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts b/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts new file mode 100644 index 00000000000000..015bd78efd4359 --- /dev/null +++ b/x-pack/plugins/security_solution/public/notes/store/notes.slice.ts @@ -0,0 +1,86 @@ +/* + * 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 { EntityState, SerializedError } from '@reduxjs/toolkit'; +import { createAsyncThunk, createEntityAdapter, createSlice } from '@reduxjs/toolkit'; +import type { State } from '../../common/store'; +import { fetchNotesByDocumentId as fetchNotesByDocumentIdApi } from '../api/api'; +import type { NormalizedEntities } from './normalize'; +import { normalizeEntities } from './normalize'; +import type { Note } from '../../../common/api/timeline'; + +export enum ReqStatus { + Idle = 'idle', + Loading = 'loading', + Succeeded = 'succeeded', + Failed = 'failed', +} + +interface HttpError { + type: 'http'; + status: number; +} + +export interface NotesState extends EntityState { + status: { + fetchNotesByDocumentId: ReqStatus; + }; + error: { + fetchNotesByDocumentId: SerializedError | HttpError | null; + }; +} + +const notesAdapter = createEntityAdapter({ + selectId: (note: Note) => note.noteId, +}); + +export const initialNotesState: NotesState = notesAdapter.getInitialState({ + status: { + fetchNotesByDocumentId: ReqStatus.Idle, + }, + error: { + fetchNotesByDocumentId: null, + }, +}); + +export const fetchNotesByDocumentId = createAsyncThunk< + NormalizedEntities, + { documentId: string }, + {} +>('notes/fetchNotesByDocumentId', async (args) => { + const { documentId } = args; + const res = await fetchNotesByDocumentIdApi(documentId); + return normalizeEntities(res); +}); + +const notesSlice = createSlice({ + name: 'notes', + initialState: initialNotesState, + reducers: {}, + extraReducers(builder) { + builder + .addCase(fetchNotesByDocumentId.pending, (state, action) => { + state.status.fetchNotesByDocumentId = ReqStatus.Loading; + }) + .addCase(fetchNotesByDocumentId.fulfilled, (state, action) => { + notesAdapter.upsertMany(state, action.payload.entities.notes); + state.status.fetchNotesByDocumentId = ReqStatus.Succeeded; + }) + .addCase(fetchNotesByDocumentId.rejected, (state, action) => { + state.status.fetchNotesByDocumentId = ReqStatus.Failed; + state.error.fetchNotesByDocumentId = action.payload ?? action.error; + }); + }, +}); + +export const notesReducer = notesSlice.reducer; + +export const { + selectAll: selectAllNotes, + selectById: selectNoteById, + selectIds: selectNoteIds, +} = notesAdapter.getSelectors((state: State) => state.notes); From 103e619c0a0049e8a4be8938715929db555899d8 Mon Sep 17 00:00:00 2001 From: Achyut Jhunjhunwala Date: Thu, 20 Jun 2024 16:50:33 +0200 Subject: [PATCH 118/123] [Dataset Quality] Fix flaky tests for Dataset Quality Summary (#184640) ## Summary As part of the PR, i have rewritten 4 of the test files for both serverless and stateful for Dataset Quality Project - `/dataset_quality/dataset_quality_summary.ts` - Closes - https://github.com/elastic/kibana/issues/178874 - Closes - https://github.com/elastic/kibana/issues/178884 - Closes - https://github.com/elastic/kibana/issues/186354 - `/dataset_quality/dataset_quality_table.ts` - Closes - https://github.com/elastic/kibana/issues/183940 (Possibly, not guaranteed) - Closes - https://github.com/elastic/kibana/issues/182353 - `/dataset_quality/dataset_quality_table_filters.ts` - Closes - https://github.com/elastic/kibana/issues/183861 - Closes - https://github.com/elastic/kibana/issues/182320 - Closes - https://github.com/elastic/kibana/issues/184852 - `/dataset_quality/dataset_quality_flyout.ts` - Closes - https://github.com/elastic/kibana/issues/184438 - Closes - https://github.com/elastic/kibana/issues/183851 - Closes - https://github.com/elastic/kibana/issues/183771 - Closes - https://github.com/elastic/kibana/issues/183525 - Closes - https://github.com/elastic/kibana/issues/183312 - Closes - https://github.com/elastic/kibana/issues/183129 - Closes - https://github.com/elastic/kibana/issues/182154 ## Why are the tests re-written - Most of the `it` were loading its own data, which add 2 problems, 1. Makes our tests slower, 2. Data cleanup becomes challenging. Now the tests simply load one master set of data and all the Functional tests can be executed on that master data. This makes our tests leaner and more functional. - Every `it` resets the page state after the tests. Like when a `it` blocks opens the Flyout, it should also close the flyout which was missing. In order to refresh the page, the `navigate` API was used, which is not good. Navigate API should only be used once to navigate to the page in the starting and then refresh events should be used if a refresh is required, or the action should be un-done in order to get the same state as previous. For ex - Sorting make update the state of the whole page. At the end of the sorting test, sorting should be reset. With these changes `it` block now only focus on pure functional testing. This means the `it` blocks can be moved around, skipped without impacting other tests - We had too much of generic tests, which could be combined into 1 `it` block and be checked together. Idea to split 1 `it` block into another is when we test for a completely different scenario. For eg - Writing a single `it` for testing different columns of a table is much more cleaner than multiple `it` for testing various columns of the same table. - Removed usage of `retry.try`. (Personal Opinion, please read it with a pinch of salt) - The retry service seems like an escape hatch (read workaround) when we don't have control over the rendering of UI elements. Better alternative is to use `retry.tryforTime` as the last resort. Also the only time i found using the whole `retry` package was when we use the `browser` package for getting URL value of refreshing page. I cannot prove yet the problem with the `browser` package but somehow it breaks the sync behaviour causing elements to be not available hence requiring these retries. I have removed `browser.refresh` completely from our code in favour of better refresh handlers using DateTimePicker Refresh action Linked Issued - https://github.com/elastic/kibana/issues/184145 --- .../public/components/flyout/fields_list.tsx | 4 +- .../get_data_stream_details/index.ts | 1 + .../apps/dataset_quality/data/logs_data.ts | 1 + .../dataset_quality/dataset_quality_flyout.ts | 649 +++++++---------- .../dataset_quality_summary.ts | 132 ++-- .../dataset_quality/dataset_quality_table.ts | 207 ++---- .../dataset_quality_table_filters.ts | 140 ++-- .../page_objects/dataset_quality.ts | 244 ++++--- .../dataset_quality/data/logs_data.ts | 1 + .../dataset_quality/dataset_quality_flyout.ts | 666 +++++++----------- .../dataset_quality_summary.ts | 133 ++-- .../dataset_quality/dataset_quality_table.ts | 210 ++---- .../dataset_quality_table_filters.ts | 137 ++-- 13 files changed, 965 insertions(+), 1560 deletions(-) diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.tsx index 4d5d561977fc58..1861d23b69a458 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.tsx @@ -22,13 +22,15 @@ export function FieldsList({ title, fields, actionsMenu: ActionsMenu, + dataTestSubj = `datasetQualityFlyoutFieldsList-${title.toLowerCase().split(' ').join('_')}`, }: { title: string; fields: Array<{ fieldTitle: string; fieldValue: ReactNode; isLoading: boolean }>; actionsMenu?: ReactNode; + dataTestSubj?: string; }) { return ( - + {title} diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts index fd15cbd884de63..52804c5d9369c0 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts @@ -61,6 +61,7 @@ export async function getDataStreamDetails({ await getDataStreamsStats({ esClient, dataStreams: [dataStream], + sizeStatsAvailable, }) ).items[0]?.lastActivity : undefined; diff --git a/x-pack/test/functional/apps/dataset_quality/data/logs_data.ts b/x-pack/test/functional/apps/dataset_quality/data/logs_data.ts index 399030d1dd3770..168aeb4b4df211 100644 --- a/x-pack/test/functional/apps/dataset_quality/data/logs_data.ts +++ b/x-pack/test/functional/apps/dataset_quality/data/logs_data.ts @@ -191,6 +191,7 @@ export function createDegradedFieldsRecord({ export const datasetNames = ['synth.1', 'synth.2', 'synth.3']; export const defaultNamespace = 'default'; +export const productionNamespace = 'production'; // Logs Data logic const MESSAGE_LOG_LEVELS: MessageWithLevel[] = [ diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts index b3a80bd673d8a1..59e11b225772a4 100644 --- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts +++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts @@ -12,6 +12,7 @@ import { datasetNames, getInitialTestLogs, getLogsForDataset, + productionNamespace, } from './data'; const integrationActions = { @@ -32,22 +33,70 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const retry = getService('retry'); const browser = getService('browser'); const to = '2024-01-01T12:00:00.000Z'; + const apacheAccessDatasetName = 'apache.access'; + const apacheAccessDatasetHumanName = 'Apache access logs'; + const apacheIntegrationId = 'apache'; + const apachePkg = { + name: 'apache', + version: '1.14.0', + }; + + const bitbucketDatasetName = 'atlassian_bitbucket.audit'; + const bitbucketDatasetHumanName = 'Bitbucket Audit Logs'; + const bitbucketPkg = { + name: 'atlassian_bitbucket', + version: '1.14.0', + }; + + const degradedDatasetName = datasetNames[2]; + + describe('Flyout', () => { + before(async () => { + // Install Apache Integration and ingest logs for it + await PageObjects.observabilityLogsExplorer.installPackage(apachePkg); + + // Install Bitbucket Integration (package which does not has Dashboards) and ingest logs for it + await PageObjects.observabilityLogsExplorer.installPackage(bitbucketPkg); + + await synthtrace.index([ + // Ingest basic logs + getInitialTestLogs({ to, count: 4 }), + // Ingest Degraded Logs + createDegradedFieldsRecord({ + to: new Date().toISOString(), + count: 2, + dataset: degradedDatasetName, + }), + // Index 15 logs for `logs-apache.access` dataset + getLogsForDataset({ + to: new Date().toISOString(), + count: 15, + dataset: apacheAccessDatasetName, + namespace: productionNamespace, + }), + // Index degraded docs for Apache integration + getLogsForDataset({ + to: new Date().toISOString(), + count: 1, + dataset: apacheAccessDatasetName, + namespace: productionNamespace, + isMalformed: true, + }), + // Index logs for Bitbucket integration + getLogsForDataset({ to, count: 10, dataset: bitbucketDatasetName }), + ]); + + await PageObjects.datasetQuality.navigateTo(); + }); - describe('Dataset quality flyout', () => { - // FLAKY: https://github.com/elastic/kibana/issues/182154 - // Added this sub describe block so that the existing flaky tests can be skipped and new ones can be added in the other describe block - describe.skip('Other dataset quality flyout tests', () => { - before(async () => { - await synthtrace.index(getInitialTestLogs({ to, count: 4 })); - await PageObjects.datasetQuality.navigateTo(); - }); - - after(async () => { - await synthtrace.clean(); - await PageObjects.observabilityLogsExplorer.removeInstalledPackages(); - }); + after(async () => { + await PageObjects.observabilityLogsExplorer.uninstallPackage(apachePkg); + await PageObjects.observabilityLogsExplorer.uninstallPackage(bitbucketPkg); + await synthtrace.clean(); + }); - it('opens the flyout for the right dataset', async () => { + describe('open flyout', () => { + it('should open the flyout for the right dataset', async () => { const testDatasetName = datasetNames[1]; await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); @@ -55,42 +104,12 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid await testSubjects.existOrFail( PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutTitle ); - }); - - it('shows the correct last activity', async () => { - const testDatasetName = datasetNames[0]; - // Update last activity for the dataset await PageObjects.datasetQuality.closeFlyout(); - await synthtrace.index( - getLogsForDataset({ to: new Date().toISOString(), count: 1, dataset: testDatasetName }) - ); - await PageObjects.datasetQuality.refreshTable(); - - const cols = await PageObjects.datasetQuality.parseDatasetTable(); - - const datasetNameCol = cols['Data Set Name']; - const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - - const testDatasetRowIndex = datasetNameColCellTexts.findIndex( - (dName: string) => dName === testDatasetName - ); - - const lastActivityText = (await cols['Last Activity'].getCellTexts())[testDatasetRowIndex]; - - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); - - const lastActivityTextExists = await PageObjects.datasetQuality.doestTextExistInFlyout( - lastActivityText, - `[data-test-subj=${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutFieldValue}]` - ); - - expect(lastActivityTextExists).to.eql(true); }); it('reflects the breakdown field state in url', async () => { - const testDatasetName = datasetNames[0]; - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); const breakdownField = 'service.name'; await PageObjects.datasetQuality.selectBreakdownField(breakdownField); @@ -109,25 +128,25 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const currentUrl = await browser.getCurrentUrl(); expect(currentUrl).to.not.contain('breakdownField'); }); + await PageObjects.datasetQuality.closeFlyout(); }); + }); - it('shows the integration details', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - const apacheIntegrationId = 'apache'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); + describe('integrations', () => { + it('should hide the integration section for non integrations', async () => { + const testDatasetName = datasetNames[1]; - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); + await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) + await testSubjects.missingOrFail( + PageObjects.datasetQuality.testSubjectSelectors + .datasetQualityFlyoutFieldsListIntegrationDetails ); - await PageObjects.datasetQuality.navigateTo(); + await PageObjects.datasetQuality.closeFlyout(); + }); + it('should shows the integration section for integrations', async () => { await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); const integrationNameElements = await PageObjects.datasetQuality.getFlyoutElementsByText( @@ -135,124 +154,141 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid apacheIntegrationId ); - await PageObjects.datasetQuality.closeFlyout(); + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors + .datasetQualityFlyoutFieldsListIntegrationDetails + ); expect(integrationNameElements.length).to.eql(1); + + await PageObjects.datasetQuality.closeFlyout(); }); - it('goes to log explorer page when open button is clicked', async () => { - const testDatasetName = datasetNames[2]; - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + it('should show the integration actions menu with correct actions', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); - await (await PageObjects.datasetQuality.getFlyoutLogsExplorerButton()).click(); + const actions = await Promise.all( + Object.values(integrationActions).map((action) => + PageObjects.datasetQuality.getIntegrationActionButtonByAction(action) + ) + ); - // Confirm dataset selector text in observability logs explorer - const datasetSelectorText = - await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); - expect(datasetSelectorText).to.eql(testDatasetName); + expect(actions.length).to.eql(3); + await PageObjects.datasetQuality.closeFlyout(); + }); + + it('should hide integration dashboard for integrations without dashboards', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); + + await testSubjects.missingOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction( + integrationActions.viewDashboards + ) + ); + await PageObjects.datasetQuality.closeFlyout(); }); - it('shows summary KPIs', async () => { + it('Should navigate to integration overview page on clicking integration overview action', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); + + const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( + integrationActions.overview + ); + + await action.click(); + + await retry.tryForTime(5000, async () => { + const currentUrl = await browser.getCurrentUrl(); + const parsedUrl = new URL(currentUrl); + + expect(parsedUrl.pathname).to.contain('/app/integrations/detail/atlassian_bitbucket'); + }); + await PageObjects.datasetQuality.navigateTo(); + }); - const apacheAccessDatasetHumanName = 'Apache access logs'; + it('should navigate to index template page in clicking Integration template', async () => { await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); + + const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( + integrationActions.template + ); + + await action.click(); - const summary = await PageObjects.datasetQuality.parseFlyoutKpis(); - expect(summary).to.eql({ - docsCountTotal: '0', - size: '0.0 B', - services: '0', - hosts: '0', - degradedDocs: '0', + await retry.tryForTime(5000, async () => { + const currentUrl = await browser.getCurrentUrl(); + const parsedUrl = new URL(currentUrl); + expect(parsedUrl.pathname).to.contain( + `/app/management/data/index_management/templates/logs-${apacheAccessDatasetName}` + ); }); + await PageObjects.datasetQuality.navigateTo(); }); - it('shows the updated KPIs', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; + it('should navigate to the selected dashboard on clicking integration dashboard action ', async () => { await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); - const summaryBefore = await PageObjects.datasetQuality.parseFlyoutKpis(); - - // Set time range to 3 days ago - const flyoutBodyContainer = await testSubjects.find( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutBody + const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( + integrationActions.viewDashboards ); - await PageObjects.datasetQuality.setDatePickerLastXUnits(flyoutBodyContainer, 3, 'd'); - // Index 2 doc 2 days ago - const time2DaysAgo = Date.now() - 2 * 24 * 60 * 60 * 1000; - await synthtrace.index( - getLogsForDataset({ - to: time2DaysAgo, - count: 2, - dataset: apacheAccessDatasetName, - isMalformed: false, - }) - ); + await action.click(); - // Index 5 degraded docs 2 days ago - await synthtrace.index( - getLogsForDataset({ - to: time2DaysAgo, - count: 5, - dataset: apacheAccessDatasetName, - isMalformed: true, - }) - ); + const dashboardButtons = await PageObjects.datasetQuality.getIntegrationDashboardButtons(); + const firstDashboardButton = await dashboardButtons[0]; + const dashboardText = await firstDashboardButton.getVisibleText(); - await PageObjects.datasetQuality.refreshFlyout(); - const summaryAfter = await PageObjects.datasetQuality.parseFlyoutKpis(); + await firstDashboardButton.click(); - expect(parseInt(summaryAfter.docsCountTotal, 10)).to.be.greaterThan( - parseInt(summaryBefore.docsCountTotal, 10) - ); + const breadcrumbText = await testSubjects.getVisibleText('breadcrumb last'); - expect(parseInt(summaryAfter.degradedDocs, 10)).to.be.greaterThan( - parseInt(summaryBefore.degradedDocs, 10) - ); + expect(breadcrumbText).to.eql(dashboardText); - expect(parseInt(summaryAfter.size, 10)).to.be.greaterThan(parseInt(summaryBefore.size, 10)); - expect(parseInt(summaryAfter.services, 10)).to.be.greaterThan( - parseInt(summaryBefore.services, 10) - ); - expect(parseInt(summaryAfter.hosts, 10)).to.be.greaterThan( - parseInt(summaryBefore.hosts, 10) - ); + await PageObjects.datasetQuality.navigateTo(); }); + }); - it('shows the right number of services', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; + describe('summary panel', () => { + it('should show summary KPIs', async () => { await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - const summaryBefore = await PageObjects.datasetQuality.parseFlyoutKpis(); - const testServices = ['test-srv-1', 'test-srv-2']; + const { docsCountTotal, degradedDocs, services, hosts, size } = + await PageObjects.datasetQuality.parseFlyoutKpis(); + expect(parseInt(docsCountTotal, 10)).to.be(226); + expect(parseInt(degradedDocs, 10)).to.be(1); + expect(parseInt(services, 10)).to.be(3); + expect(parseInt(hosts, 10)).to.be(52); + expect(parseInt(size, 10)).to.be.greaterThan(0); - // Index 2 docs with different services - const timeNow = Date.now(); - await synthtrace.index( - getLogsForDataset({ - to: timeNow, - count: 2, - dataset: apacheAccessDatasetName, - isMalformed: false, - services: testServices, - }) - ); + await PageObjects.datasetQuality.closeFlyout(); + }); + }); - await PageObjects.datasetQuality.refreshFlyout(); - const summaryAfter = await PageObjects.datasetQuality.parseFlyoutKpis(); + describe('navigation', () => { + it('should go to log explorer page when the open in log explorer button is clicked', async () => { + const testDatasetName = datasetNames[2]; + await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); - expect(parseInt(summaryAfter.services, 10)).to.eql( - parseInt(summaryBefore.services, 10) + testServices.length - ); + const logExplorerButton = await PageObjects.datasetQuality.getFlyoutLogsExplorerButton(); + + await logExplorerButton.click(); + + // Confirm dataset selector text in observability logs explorer + const datasetSelectorText = + await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); + expect(datasetSelectorText).to.eql(testDatasetName); + + // Should bring back the test to the dataset quality page + await PageObjects.datasetQuality.navigateTo(); }); - it('goes to log explorer for degraded docs when show all is clicked', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; + it('should go log explorer for degraded docs when the show all button is clicked', async () => { await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); const degradedDocsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.degradedDocs}`; @@ -266,11 +302,13 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid await browser.closeCurrentWindow(); await browser.switchTab(0); + + await PageObjects.datasetQuality.closeFlyout(); }); // Blocked by https://github.com/elastic/kibana/issues/181705 + // Its a test written ahead of its time. it.skip('goes to infra hosts for hosts when show all is clicked', async () => { - const apacheAccessDatasetHumanName = 'Apache access logs'; await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); const hostsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.hosts}`; @@ -286,307 +324,132 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid await browser.closeCurrentWindow(); await browser.switchTab(0); - }); - it('Integration actions menu is present with correct actions', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); + await PageObjects.datasetQuality.closeFlyout(); + }); + }); - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); + describe('degraded fields table', () => { + it(' should show empty degraded fields table when no degraded fields are present', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(datasetNames[0]); - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedTableNoData ); - await PageObjects.datasetQuality.navigateTo(); + await PageObjects.datasetQuality.closeFlyout(); + }); - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); + it('should show the degraded fields table with data when present', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - const actions = await Promise.all( - Object.values(integrationActions).map((action) => - PageObjects.datasetQuality.getIntegrationActionButtonByAction(action) - ) + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable ); - expect(actions.length).to.eql(3); - }); + const rows = + await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); - it('Integration dashboard action hidden for integrations without dashboards', async () => { - const bitbucketDatasetName = 'atlassian_bitbucket.audit'; - const bitbucketDatasetHumanName = 'Bitbucket Audit Logs'; + expect(rows.length).to.eql(2); - await PageObjects.observabilityLogsExplorer.navigateTo(); + await PageObjects.datasetQuality.closeFlyout(); + }); - // Add initial integrations - await PageObjects.observabilityLogsExplorer.installPackage({ - name: 'atlassian_bitbucket', - version: '1.14.0', - }); + it('should display Spark Plot for every row of degraded fields', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - // Index 10 logs for `atlassian_bitbucket.audit` dataset - await synthtrace.index(getLogsForDataset({ to, count: 10, dataset: bitbucketDatasetName })); + const rows = + await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); - await PageObjects.datasetQuality.navigateTo(); + const sparkPlots = await testSubjects.findAll( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot + ); - await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); + expect(rows.length).to.be(sparkPlots.length); - await testSubjects.missingOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction( - integrationActions.viewDashboards - ) - ); + await PageObjects.datasetQuality.closeFlyout(); }); - it('Integration overview action should navigate to the integration overview page', async () => { - const bitbucketDatasetName = 'atlassian_bitbucket.audit'; - const bitbucketDatasetHumanName = 'Bitbucket Audit Logs'; + it('should sort the table when the count table header is clicked', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - await PageObjects.observabilityLogsExplorer.navigateTo(); + const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); - // Add initial integrations - await PageObjects.observabilityLogsExplorer.installPackage({ - name: 'atlassian_bitbucket', - version: '1.14.0', - }); + const countColumn = table['Docs count']; + const cellTexts = await countColumn.getCellTexts(); - // Index 10 logs for `atlassian_bitbucket.audit` dataset - await synthtrace.index(getLogsForDataset({ to, count: 10, dataset: bitbucketDatasetName })); + await countColumn.sort('ascending'); + const sortedCellTexts = await countColumn.getCellTexts(); - await PageObjects.datasetQuality.navigateTo(); + expect(cellTexts.reverse()).to.eql(sortedCellTexts); - await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); + await PageObjects.datasetQuality.closeFlyout(); + }); - const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( - integrationActions.overview - ); + it('should update the URL when the table is sorted', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - await action.click(); + const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); + const countColumn = table['Docs count']; await retry.tryForTime(5000, async () => { const currentUrl = await browser.getCurrentUrl(); const parsedUrl = new URL(currentUrl); + const pageState = parsedUrl.searchParams.get('pageState'); - expect(parsedUrl.pathname).to.contain('/app/integrations/detail/atlassian_bitbucket'); + expect(decodeURIComponent(pageState as string)).to.contain( + 'sort:(direction:desc,field:count)' + ); }); - }); - - it('Integration template action should navigate to the index template page', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) - ); - - await PageObjects.datasetQuality.navigateTo(); - - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); + countColumn.sort('ascending'); await retry.tryForTime(5000, async () => { - const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( - integrationActions.template - ); - - await action.click(); - const currentUrl = await browser.getCurrentUrl(); const parsedUrl = new URL(currentUrl); - expect(parsedUrl.pathname).to.contain( - `/app/management/data/index_management/templates/logs-${apacheAccessDatasetName}` - ); - }); - }); - - it('Integration dashboard action should navigate to the selected dashboard', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) - ); - - await PageObjects.datasetQuality.navigateTo(); - - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); - - const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( - integrationActions.viewDashboards - ); - - await action.click(); - - const dashboardButtons = await PageObjects.datasetQuality.getIntegrationDashboardButtons(); - const firstDashboardButton = await dashboardButtons[0]; - const dashboardText = await firstDashboardButton.getVisibleText(); - - await firstDashboardButton.click(); - - const breadcrumbText = await testSubjects.getVisibleText('breadcrumb last'); - - expect(breadcrumbText).to.eql(dashboardText); - }); - }); - - // The above describe block has some failing/flaky tests which will - // be fixed as part of the tech debt mentioned here - // https://github.com/elastic/kibana/issues/184145 - // Until then, the below describe block is added to cover the tests for the - // newly added degraded Fields Table. This must be merged under the above - // describe block once the tech debt is fixed. - describe('Dataset quality flyout with degraded fields', () => { - const goodDatasetName = 'good'; - const degradedDatasetName = 'degraded'; - const today = new Date().toISOString(); - - describe('Degraded Fields Table with common data', () => { - before(async () => { - await synthtrace.index([ - getLogsForDataset({ - to: today, - count: 2, - dataset: goodDatasetName, - isMalformed: false, - }), - createDegradedFieldsRecord({ - to: today, - count: 2, - dataset: degradedDatasetName, - }), - ]); - await PageObjects.datasetQuality.navigateTo(); - }); + const pageState = parsedUrl.searchParams.get('pageState'); - after(async () => { - await synthtrace.clean(); - }); - - it('shows the degraded fields table with no data when no degraded fields are present', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(goodDatasetName); - - await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedTableNoData - ); - - await PageObjects.datasetQuality.closeFlyout(); - }); - - it('should load the degraded fields table with data', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - - await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable + expect(decodeURIComponent(pageState as string)).to.contain( + 'sort:(direction:asc,field:count)' ); - - const rows = - await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); - - expect(rows.length).to.eql(2); - - await PageObjects.datasetQuality.closeFlyout(); }); - it('should display Spark Plot for every row of degraded fields', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - - const rows = - await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); - - const sparkPlots = await testSubjects.findAll( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot - ); - - expect(rows.length).to.be(sparkPlots.length); - - await PageObjects.datasetQuality.closeFlyout(); - }); - - it('should sort the table when the count table header is clicked', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - - const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); - - const countColumn = table['Docs count']; - const cellTexts = await countColumn.getCellTexts(); - - await countColumn.sort('ascending'); - const sortedCellTexts = await countColumn.getCellTexts(); - - expect(cellTexts.reverse()).to.eql(sortedCellTexts); - - await PageObjects.datasetQuality.closeFlyout(); - }); + await PageObjects.datasetQuality.closeFlyout(); }); - describe('Degraded Fields Table with data ingestion', () => { - before(async () => { - await synthtrace.index([ - getLogsForDataset({ - to: today, - count: 2, - dataset: goodDatasetName, - isMalformed: false, - }), - createDegradedFieldsRecord({ - to: today, - count: 2, - dataset: degradedDatasetName, - }), - ]); - await PageObjects.datasetQuality.navigateTo(); - }); - - after(async () => { - await synthtrace.clean(); - }); + // This is the only test which ingest data during the test. + // This block tests the refresh behavior of the degraded fields table. + // Even though this test ingest data, it can also be freely moved inside + // this describe block, and it won't affect any of the existing tests + it('should update the table when new data is ingested and the flyout is refreshed using the time selector', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - it('should update the table when new data is ingested and the flyout is refreshed using the time selector', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); - const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); + const countColumn = table['Docs count']; + const cellTexts = await countColumn.getCellTexts(); - const countColumn = table['Docs count']; - const cellTexts = await countColumn.getCellTexts(); + await synthtrace.index([ + createDegradedFieldsRecord({ + to: new Date().toISOString(), + count: 2, + dataset: degradedDatasetName, + }), + ]); - await synthtrace.index([ - createDegradedFieldsRecord({ - to: today, - count: 2, - dataset: degradedDatasetName, - }), - ]); + await PageObjects.datasetQuality.refreshFlyout(); - await PageObjects.datasetQuality.refreshFlyout(); + const updatedTable = await PageObjects.datasetQuality.parseDegradedFieldTable(); + const updatedCountColumn = updatedTable['Docs count']; - const updatedCellTexts = await countColumn.getCellTexts(); + const updatedCellTexts = await updatedCountColumn.getCellTexts(); - const singleValuePreviously = parseInt(cellTexts[0], 10); - const singleValueNow = parseInt(updatedCellTexts[0], 10); + const singleValuePreviously = parseInt(cellTexts[0], 10); + const singleValueNow = parseInt(updatedCellTexts[0], 10); - expect(singleValueNow).to.be(singleValuePreviously * 2); + expect(singleValueNow).to.be.greaterThan(singleValuePreviously); - await PageObjects.datasetQuality.closeFlyout(); - }); + await PageObjects.datasetQuality.closeFlyout(); }); }); }); diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_summary.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_summary.ts index c3bc9ea3145a57..be70275f0874d0 100644 --- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_summary.ts +++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_summary.ts @@ -17,21 +17,48 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid 'datasetQuality', ]); const synthtrace = getService('logSynthtraceEsClient'); - const browser = getService('browser'); - const retry = getService('retry'); const to = '2024-01-01T12:00:00.000Z'; + const ingestDataForSummary = async () => { + // Ingest documents for 3 type of datasets + return synthtrace.index([ + // Ingest good data to all 3 datasets + getInitialTestLogs({ to, count: 4 }), + // Ingesting poor data to one dataset + getLogsForDataset({ + to: Date.now(), + count: 1, + dataset: datasetNames[1], + isMalformed: true, + }), + // Ingesting degraded docs into another dataset by ingesting malformed 1st and then good data + getLogsForDataset({ + to: Date.now(), + count: 1, + dataset: datasetNames[2], + isMalformed: true, + }), + getLogsForDataset({ + to: Date.now(), + count: 10, + dataset: datasetNames[2], + isMalformed: false, + }), + ]); + }; + describe('Dataset quality summary', () => { before(async () => { - await synthtrace.index(getInitialTestLogs({ to, count: 4 })); await PageObjects.datasetQuality.navigateTo(); }); - after(async () => { + afterEach(async () => { await synthtrace.clean(); }); - it('shows poor, degraded and good count', async () => { + it('shows poor, degraded and good count as 0 and all dataset as healthy', async () => { + await synthtrace.index(getInitialTestLogs({ to, count: 4 })); + await PageObjects.datasetQuality.refreshTable(); const summary = await PageObjects.datasetQuality.parseSummaryPanel(); expect(summary).to.eql({ datasetHealthPoor: '0', @@ -42,92 +69,21 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid }); }); - it('updates the poor count when degraded docs are ingested', async () => { - // Index malformed document with current timestamp - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 1, - dataset: datasetNames[2], - isMalformed: true, - }) - ); - - await browser.refresh(); - await PageObjects.datasetQuality.waitUntilSummaryPanelLoaded(); - - await retry.try(async () => { - const summary = await PageObjects.datasetQuality.parseSummaryPanel(); - const { estimatedData, ...restOfSummary } = summary; - expect(restOfSummary).to.eql({ - datasetHealthPoor: '1', - datasetHealthDegraded: '0', - datasetHealthGood: '2', - activeDatasets: '1 of 3', - }); - }); - }); - - it('updates the degraded count when degraded docs are ingested', async () => { - // Index malformed document with current timestamp - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 1, - dataset: datasetNames[1], - isMalformed: true, - }) - ); - - // Index healthy documents - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 10, - dataset: datasetNames[1], - isMalformed: false, - }) - ); + it('shows updated count for poor, degraded and good datasets, estimated size and updates active datasets', async () => { + await ingestDataForSummary(); + await PageObjects.datasetQuality.refreshTable(); - await browser.refresh(); - await PageObjects.datasetQuality.waitUntilSummaryPanelLoaded(); - - await retry.try(async () => { - const { estimatedData, ...restOfSummary } = - await PageObjects.datasetQuality.parseSummaryPanel(); - expect(restOfSummary).to.eql({ - datasetHealthPoor: '1', - datasetHealthDegraded: '1', - datasetHealthGood: '1', - activeDatasets: '2 of 3', - }); + const summary = await PageObjects.datasetQuality.parseSummaryPanel(); + const { estimatedData, ...restOfSummary } = summary; + expect(restOfSummary).to.eql({ + datasetHealthPoor: '1', + datasetHealthDegraded: '1', + datasetHealthGood: '1', + activeDatasets: '2 of 3', }); - }); - - it('updates active datasets and estimated data KPIs', async () => { - const { estimatedData: existingEstimatedData } = - await PageObjects.datasetQuality.parseSummaryPanel(); - // Index document at current time to mark dataset as active - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 4, - dataset: datasetNames[0], - isMalformed: false, - }) - ); - - await browser.refresh(); // Summary panel doesn't update reactively - await PageObjects.datasetQuality.waitUntilSummaryPanelLoaded(); - - await retry.try(async () => { - const { activeDatasets: updatedActiveDatasets, estimatedData: updatedEstimatedData } = - await PageObjects.datasetQuality.parseSummaryPanel(); - - expect(updatedActiveDatasets).to.eql('3 of 3'); - expect(updatedEstimatedData).to.not.eql(existingEstimatedData); - }); + const sizeInNumber = parseFloat(estimatedData.split(' ')[0]); + expect(sizeInNumber).to.be.greaterThan(0); }); }); } diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_table.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_table.ts index 51707db1f852c4..fb6c6ed9b519f6 100644 --- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_table.ts +++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_table.ts @@ -7,7 +7,13 @@ import expect from '@kbn/expect'; import { DatasetQualityFtrProviderContext } from './config'; -import { datasetNames, defaultNamespace, getInitialTestLogs, getLogsForDataset } from './data'; +import { + datasetNames, + defaultNamespace, + getInitialTestLogs, + getLogsForDataset, + productionNamespace, +} from './data'; export default function ({ getService, getPageObjects }: DatasetQualityFtrProviderContext) { const PageObjects = getPageObjects([ @@ -17,40 +23,78 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid 'datasetQuality', ]); const synthtrace = getService('logSynthtraceEsClient'); - const testSubjects = getService('testSubjects'); - const retry = getService('retry'); const to = '2024-01-01T12:00:00.000Z'; + const apacheAccessDatasetName = 'apache.access'; + const apacheAccessDatasetHumanName = 'Apache access logs'; + const pkg = { + name: 'apache', + version: '1.14.0', + }; describe('Dataset quality table', () => { before(async () => { - await synthtrace.index(getInitialTestLogs({ to, count: 4 })); + // Install Integration and ingest logs for it + await PageObjects.observabilityLogsExplorer.installPackage(pkg); + // Ingest basic logs + await synthtrace.index([ + // Ingest basic logs + getInitialTestLogs({ to, count: 4 }), + // Ingest Degraded Logs + getLogsForDataset({ + to: new Date().toISOString(), + count: 1, + dataset: datasetNames[2], + isMalformed: true, + }), + // Index 10 logs for `logs-apache.access` dataset + getLogsForDataset({ + to, + count: 10, + dataset: apacheAccessDatasetName, + namespace: productionNamespace, + }), + ]); await PageObjects.datasetQuality.navigateTo(); }); after(async () => { await synthtrace.clean(); - await PageObjects.observabilityLogsExplorer.removeInstalledPackages(); + await PageObjects.observabilityLogsExplorer.uninstallPackage(pkg); }); - it('shows the right number of rows in correct order', async () => { + it('shows sort by dataset name and show namespace', async () => { const cols = await PageObjects.datasetQuality.parseDatasetTable(); - const datasetNameCol = cols['Data Set Name']; await datasetNameCol.sort('descending'); const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTexts).to.eql([...datasetNames].reverse()); + expect(datasetNameColCellTexts).to.eql( + [apacheAccessDatasetHumanName, ...datasetNames].reverse() + ); const namespaceCol = cols.Namespace; const namespaceColCellTexts = await namespaceCol.getCellTexts(); - expect(namespaceColCellTexts).to.eql([defaultNamespace, defaultNamespace, defaultNamespace]); + expect(namespaceColCellTexts).to.eql([ + defaultNamespace, + defaultNamespace, + defaultNamespace, + productionNamespace, + ]); - const degradedDocsCol = cols['Degraded Docs (%)']; - const degradedDocsColCellTexts = await degradedDocsCol.getCellTexts(); - expect(degradedDocsColCellTexts).to.eql(['0%', '0%', '0%']); + // Cleaning the sort + await datasetNameCol.sort('ascending'); + }); + it('shows the last activity', async () => { + const cols = await PageObjects.datasetQuality.parseDatasetTable(); const lastActivityCol = cols['Last Activity']; - const lastActivityColCellTexts = await lastActivityCol.getCellTexts(); - expect(lastActivityColCellTexts).to.eql([ + const activityCells = await lastActivityCol.getCellTexts(); + const lastActivityCell = activityCells[activityCells.length - 1]; + const restActivityCells = activityCells.slice(0, -1); + + // The first cell of lastActivity should have data + expect(lastActivityCell).to.not.eql(PageObjects.datasetQuality.texts.noActivityText); + // The rest of the rows must show no activity + expect(restActivityCells).to.eql([ PageObjects.datasetQuality.texts.noActivityText, PageObjects.datasetQuality.texts.noActivityText, PageObjects.datasetQuality.texts.noActivityText, @@ -59,111 +103,30 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid it('shows degraded docs percentage', async () => { const cols = await PageObjects.datasetQuality.parseDatasetTable(); - const datasetNameCol = cols['Data Set Name']; - await datasetNameCol.sort('ascending'); const degradedDocsCol = cols['Degraded Docs (%)']; const degradedDocsColCellTexts = await degradedDocsCol.getCellTexts(); - expect(degradedDocsColCellTexts).to.eql(['0%', '0%', '0%']); - - // Index malformed document with current timestamp - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 1, - dataset: datasetNames[2], - isMalformed: true, - }) - ); - - // Set time range to Last 5 minute - const filtersContainer = await testSubjects.find( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFiltersContainer - ); - await PageObjects.datasetQuality.setDatePickerLastXUnits(filtersContainer, 5, 'm'); - - const updatedDegradedDocsColCellTexts = await degradedDocsCol.getCellTexts(); - expect(updatedDegradedDocsColCellTexts[2]).to.not.eql('0%'); + expect(degradedDocsColCellTexts).to.eql(['0%', '0%', '0%', '100%']); }); - it('shows the updated size of the index', async () => { - const testDatasetIndex = 2; + it('shows the value in the size column', async () => { const cols = await PageObjects.datasetQuality.parseDatasetTable(); - const datasetNameCol = cols['Data Set Name']; - await datasetNameCol.sort('ascending'); - const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - - const datasetToUpdateRowIndex = datasetNameColCellTexts.findIndex( - (dName: string) => dName === datasetNames[testDatasetIndex] - ); const sizeColCellTexts = await cols.Size.getCellTexts(); - const beforeSize = sizeColCellTexts[datasetToUpdateRowIndex]; + const sizeGreaterThanZero = sizeColCellTexts[3]; + const sizeEqualToZero = sizeColCellTexts[2]; - // Index documents with current timestamp - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 4, - dataset: datasetNames[testDatasetIndex], - isMalformed: false, - }) - ); - - const colsAfterUpdate = await PageObjects.datasetQuality.parseDatasetTable(); - - // Assert that size has changed - await retry.tryForTime(15000, async () => { - // Refresh the table - await PageObjects.datasetQuality.refreshTable(); - const updatedSizeColCellTexts = await colsAfterUpdate.Size.getCellTexts(); - expect(updatedSizeColCellTexts[datasetToUpdateRowIndex]).to.not.eql(beforeSize); - }); - }); - - it('sorts by dataset name', async () => { - // const header = await PageObjects.datasetQuality.getDatasetTableHeader('Data Set Name'); - const cols = await PageObjects.datasetQuality.parseDatasetTable(); - const datasetNameCol = cols['Data Set Name']; - - // Sort ascending - await datasetNameCol.sort('ascending'); - const cellTexts = await datasetNameCol.getCellTexts(); - - const datasetNamesAsc = [...datasetNames].sort(); - - expect(cellTexts).to.eql(datasetNamesAsc); + expect(sizeGreaterThanZero).to.not.eql('0.0 KB'); + expect(sizeEqualToZero).to.eql('0.0 B'); }); it('shows dataset from integration', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) - ); - - await PageObjects.datasetQuality.navigateTo(); - const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; - // Sort ascending - await datasetNameCol.sort('ascending'); const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - const datasetNamesAsc = [...datasetNames, apacheAccessDatasetHumanName].sort(); - - // Assert there are 4 rows - expect(datasetNameColCellTexts.length).to.eql(4); - - expect(datasetNameColCellTexts).to.eql(datasetNamesAsc); + expect(datasetNameColCellTexts[0]).to.eql(apacheAccessDatasetHumanName); }); it('goes to log explorer page when opened', async () => { @@ -179,50 +142,12 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const datasetSelectorText = await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); expect(datasetSelectorText).to.eql(datasetName); - }); - it('shows the last activity when in time range', async () => { + // Return to Dataset Quality Page await PageObjects.datasetQuality.navigateTo(); - const cols = await PageObjects.datasetQuality.parseDatasetTable(); - const lastActivityCol = cols['Last Activity']; - const datasetNameCol = cols['Data Set Name']; - - // Set time range to Last 1 minute - const filtersContainer = await testSubjects.find( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFiltersContainer - ); - - await PageObjects.datasetQuality.setDatePickerLastXUnits(filtersContainer, 1, 's'); - const lastActivityColCellTexts = await lastActivityCol.getCellTexts(); - expect(lastActivityColCellTexts).to.eql([ - PageObjects.datasetQuality.texts.noActivityText, - PageObjects.datasetQuality.texts.noActivityText, - PageObjects.datasetQuality.texts.noActivityText, - PageObjects.datasetQuality.texts.noActivityText, - ]); - - const datasetToUpdate = datasetNames[0]; - await synthtrace.index( - getLogsForDataset({ to: new Date().toISOString(), count: 1, dataset: datasetToUpdate }) - ); - const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - const datasetToUpdateRowIndex = datasetNameColCellTexts.findIndex( - (dName: string) => dName === datasetToUpdate - ); - - await PageObjects.datasetQuality.setDatePickerLastXUnits(filtersContainer, 1, 'h'); - - await retry.tryForTime(5000, async () => { - const updatedLastActivityColCellTexts = await lastActivityCol.getCellTexts(); - expect(updatedLastActivityColCellTexts[datasetToUpdateRowIndex]).to.not.eql( - PageObjects.datasetQuality.texts.noActivityText - ); - }); }); it('hides inactive datasets', async () => { - await PageObjects.datasetQuality.waitUntilTableLoaded(); - // Get number of rows with Last Activity not equal to "No activity in the selected timeframe" const cols = await PageObjects.datasetQuality.parseDatasetTable(); const lastActivityCol = cols['Last Activity']; diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_table_filters.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_table_filters.ts index ac118a5c1d1cc9..3c8c3e702d5767 100644 --- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_table_filters.ts +++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_table_filters.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { DatasetQualityFtrProviderContext } from './config'; -import { datasetNames, defaultNamespace, getInitialTestLogs, getLogsForDataset } from './data'; +import { datasetNames, getInitialTestLogs, getLogsForDataset, productionNamespace } from './data'; export default function ({ getService, getPageObjects }: DatasetQualityFtrProviderContext) { const PageObjects = getPageObjects([ @@ -19,55 +19,73 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const synthtrace = getService('logSynthtraceEsClient'); const testSubjects = getService('testSubjects'); const to = '2024-01-01T12:00:00.000Z'; + const apacheAccessDatasetName = 'apache.access'; + const apacheAccessDatasetHumanName = 'Apache access logs'; + const apacheIntegrationName = 'Apache HTTP Server'; + const pkg = { + name: 'apache', + version: '1.14.0', + }; + const allDatasetNames = [apacheAccessDatasetHumanName, ...datasetNames]; describe('Dataset quality table filters', () => { before(async () => { - await synthtrace.index(getInitialTestLogs({ to, count: 4 })); + // Install Integration and ingest logs for it + await PageObjects.observabilityLogsExplorer.installPackage(pkg); + // Ingest basic logs + await synthtrace.index([ + // Ingest basic logs + getInitialTestLogs({ to, count: 4 }), + // Ingest Degraded Logs + getLogsForDataset({ + to: new Date().toISOString(), + count: 1, + dataset: datasetNames[2], + isMalformed: true, + }), + // Index 10 logs for `logs-apache.access` dataset + getLogsForDataset({ + to, + count: 10, + dataset: apacheAccessDatasetName, + namespace: productionNamespace, + }), + ]); await PageObjects.datasetQuality.navigateTo(); }); after(async () => { + await PageObjects.observabilityLogsExplorer.uninstallPackage(pkg); await synthtrace.clean(); - await PageObjects.observabilityLogsExplorer.removeInstalledPackages(); - }); - - it('hides inactive datasets when toggled', async () => { - const initialRows = await PageObjects.datasetQuality.getDatasetTableRows(); - expect(initialRows.length).to.eql(3); - - await PageObjects.datasetQuality.toggleShowInactiveDatasets(); - - const afterToggleRows = await PageObjects.datasetQuality.getDatasetTableRows(); - expect(afterToggleRows.length).to.eql(1); - - await PageObjects.datasetQuality.toggleShowInactiveDatasets(); - - const afterReToggleRows = await PageObjects.datasetQuality.getDatasetTableRows(); - expect(afterReToggleRows.length).to.eql(3); }); it('shows full dataset names when toggled', async () => { const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTexts).to.eql(datasetNames); + expect(datasetNameColCellTexts).to.eql(allDatasetNames); await PageObjects.datasetQuality.toggleShowFullDatasetNames(); const datasetNameColCellTextsAfterToggle = await datasetNameCol.getCellTexts(); - const duplicateNames = datasetNames.map((name) => `${name}\n${name}`); + const duplicateNames = [ + `${apacheAccessDatasetHumanName}\n${apacheAccessDatasetName}`, + ...datasetNames.map((name) => `${name}\n${name}`), + ]; + expect(datasetNameColCellTextsAfterToggle).to.eql(duplicateNames); + // resetting the toggle await PageObjects.datasetQuality.toggleShowFullDatasetNames(); const datasetNameColCellTextsAfterReToggle = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTextsAfterReToggle).to.eql(datasetNames); + expect(datasetNameColCellTextsAfterReToggle).to.eql(allDatasetNames); }); it('searches the datasets', async () => { const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTexts).to.eql(datasetNames); + expect(datasetNameColCellTexts).to.eql(allDatasetNames); // Search for a dataset await testSubjects.setValue( @@ -79,33 +97,16 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const datasetNameColAfterSearch = colsAfterSearch['Data Set Name']; const datasetNameColCellTextsAfterSearch = await datasetNameColAfterSearch.getCellTexts(); expect(datasetNameColCellTextsAfterSearch).to.eql([datasetNames[2]]); - await testSubjects.setValue( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFilterBarFieldSearch, - '' - ); + + // Reset the search field + await testSubjects.click('clearSearchButton'); }); it('filters for integration', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - const apacheIntegrationName = 'Apache HTTP Server'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) - ); - - await PageObjects.datasetQuality.navigateTo(); - const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTexts).to.eql([apacheAccessDatasetHumanName, ...datasetNames]); + expect(datasetNameColCellTexts).to.eql(allDatasetNames); // Filter for integration await PageObjects.datasetQuality.filterForIntegrations([apacheIntegrationName]); @@ -113,65 +114,33 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const colsAfterFilter = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameColAfterFilter = colsAfterFilter['Data Set Name']; const datasetNameColCellTextsAfterFilter = await datasetNameColAfterFilter.getCellTexts(); + expect(datasetNameColCellTextsAfterFilter).to.eql([apacheAccessDatasetHumanName]); + // Reset the filter by selecting from the dropdown again + await PageObjects.datasetQuality.filterForIntegrations([apacheIntegrationName]); }); it('filters for namespace', async () => { - const apacheAccessDatasetName = 'apache.access'; - const datasetNamespace = 'prod'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ - to, - count: 10, - dataset: apacheAccessDatasetName, - namespace: datasetNamespace, - }) - ); - - await PageObjects.datasetQuality.navigateTo(); - // Get default namespaces const cols = await PageObjects.datasetQuality.parseDatasetTable(); const namespaceCol = cols.Namespace; const namespaceColCellTexts = await namespaceCol.getCellTexts(); - expect(namespaceColCellTexts).to.contain(defaultNamespace); + expect(namespaceColCellTexts).to.contain(productionNamespace); - // Filter for prod namespace - await PageObjects.datasetQuality.filterForNamespaces([datasetNamespace]); + // Filter for production namespace + await PageObjects.datasetQuality.filterForNamespaces([productionNamespace]); const colsAfterFilter = await PageObjects.datasetQuality.parseDatasetTable(); const namespaceColAfterFilter = colsAfterFilter.Namespace; const namespaceColCellTextsAfterFilter = await namespaceColAfterFilter.getCellTexts(); - expect(namespaceColCellTextsAfterFilter).to.eql([datasetNamespace]); + expect(namespaceColCellTextsAfterFilter).to.eql([productionNamespace]); + // Reset the namespace by selecting from the dropdown again + await PageObjects.datasetQuality.filterForNamespaces([productionNamespace]); }); it('filters for quality', async () => { - const apacheAccessDatasetName = 'apache.access'; const expectedQuality = 'Poor'; - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ - to: new Date().toISOString(), - count: 10, - dataset: apacheAccessDatasetName, - isMalformed: true, - }) - ); - - await PageObjects.datasetQuality.navigateTo(); - // Get default quality const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetQuality = cols['Data Set Quality']; @@ -186,6 +155,9 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const datasetQualityCellTextsAfterFilter = await datasetQualityAfterFilter.getCellTexts(); expect(datasetQualityCellTextsAfterFilter).to.eql([expectedQuality]); + + // Reset the namespace by selecting from the dropdown again + await PageObjects.datasetQuality.filterForQualities([expectedQuality]); }); }); } diff --git a/x-pack/test/functional/page_objects/dataset_quality.ts b/x-pack/test/functional/page_objects/dataset_quality.ts index 3722a10849aff7..d9b274e1585367 100644 --- a/x-pack/test/functional/page_objects/dataset_quality.ts +++ b/x-pack/test/functional/page_objects/dataset_quality.ts @@ -51,12 +51,26 @@ type SummaryPanelKpi = Record< type FlyoutKpi = Record<'docsCountTotal' | 'size' | 'services' | 'hosts' | 'degradedDocs', string>; +const texts = { + noActivityText: 'No activity in the selected timeframe', + datasetHealthPoor: 'Poor', + datasetHealthDegraded: 'Degraded', + datasetHealthGood: 'Good', + activeDatasets: 'Active Data Sets', + estimatedData: 'Estimated Data', + docsCountTotal: 'Docs count (total)', + size: 'Size', + services: 'Services', + hosts: 'Hosts', + degradedDocs: 'Degraded docs', +}; + export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProviderContext) { const PageObjects = getPageObjects(['common']); const testSubjects = getService('testSubjects'); const euiSelectable = getService('selectable'); - const retry = getService('retry'); const find = getService('find'); + const retry = getService('retry'); const selectors = { datasetQualityTable: '[data-test-subj="datasetQualityTable"]', @@ -80,6 +94,8 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv datasetQualitySparkPlot: 'datasetQualitySparkPlot', datasetQualityHeaderButton: 'datasetQualityHeaderButton', datasetQualityFlyoutFieldValue: 'datasetQualityFlyoutFieldValue', + datasetQualityFlyoutFieldsListIntegrationDetails: + 'datasetQualityFlyoutFieldsList-integration_details', datasetQualityFlyoutIntegrationActionsButton: 'datasetQualityFlyoutIntegrationActionsButton', datasetQualityFlyoutIntegrationAction: (action: string) => `datasetQualityFlyoutIntegrationAction${action}`, @@ -147,13 +163,17 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv await find.waitForDeletedByCssSelector('.euiFlyoutBody .euiBasicTable-loading', 20 * 1000); }, - async waitUntilSummaryPanelLoaded() { + async waitUntilSummaryPanelLoaded(isStateful: boolean = true) { await testSubjects.missingOrFail(`datasetQuality-${texts.activeDatasets}-loading`); - await testSubjects.missingOrFail(`datasetQuality-${texts.estimatedData}-loading`); + if (isStateful) { + await testSubjects.missingOrFail(`datasetQuality-${texts.estimatedData}-loading`); + } }, async parseSummaryPanel(excludeKeys: string[] = []): Promise { - await this.waitUntilSummaryPanelLoaded(); + const isStateful = !excludeKeys.includes('estimatedData'); + + await this.waitUntilSummaryPanelLoaded(isStateful); const kpiTitleAndKeys = [ { title: texts.datasetHealthPoor, key: 'datasetHealthPoor' }, @@ -221,8 +241,9 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv }, async parseDatasetTable() { + await this.waitUntilTableLoaded(); const table = await this.getDatasetsTable(); - return parseDatasetTable(table, [ + return this.parseTable(table, [ '0', 'Data Set Name', 'Namespace', @@ -235,8 +256,9 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv }, async parseDegradedFieldTable() { + await this.waitUntilTableInFlyoutLoaded(); const table = await this.getDatasetQualityFlyoutDegradedFieldTable(); - return parseDatasetTable(table, ['Field', 'Docs count', 'Last Occurrence']); + return this.parseTable(table, ['Field', 'Docs count', 'Last Occurrence']); }, async filterForIntegrations(integrations: string[]) { @@ -272,29 +294,32 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv }, async openDatasetFlyout(datasetName: string) { + await this.waitUntilTableLoaded(); const cols = await this.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); const testDatasetRowIndex = datasetNameColCellTexts.findIndex( (dName) => dName === datasetName ); - const expanderColumn = cols['0']; - let expanderButtons: WebElementWrapper[]; - await retry.try(async () => { - expanderButtons = await expanderColumn.getCellChildren( - `[data-test-subj=${testSubjectSelectors.datasetQualityExpandButton}]` - ); - expect(expanderButtons.length).to.be.greaterThan(0); - - // Check if 'title' attribute is "Expand" or "Collapse" - const isCollapsed = - (await expanderButtons[testDatasetRowIndex].getAttribute('title')) === 'Expand'; - - // Open if collapsed - if (isCollapsed) { - await expanderButtons[testDatasetRowIndex].click(); - } - }); + + expect(testDatasetRowIndex).to.be.greaterThan(-1); + + const expandColumn = cols['0']; + const expandButtons = await expandColumn.getCellChildren( + `[data-test-subj=${testSubjectSelectors.datasetQualityExpandButton}]` + ); + + expect(expandButtons.length).to.be.greaterThan(0); + + const datasetExpandButton = expandButtons[testDatasetRowIndex]; + + // Check if 'title' attribute is "Expand" or "Collapse" + const isCollapsed = (await datasetExpandButton.getAttribute('title')) === 'Expand'; + + // Open if collapsed + if (isCollapsed) { + await datasetExpandButton.click(); + } }, async closeFlyout() { @@ -430,6 +455,85 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv fieldText ); }, + + async parseTable(tableWrapper: WebElementWrapper, columnNamesOrIndexes: string[]) { + const headerElementWrappers = await tableWrapper.findAllByCssSelector('thead th, thead td'); + + const result: Record< + string, + { + columnNameOrIndex: string; + sortDirection?: 'ascending' | 'descending'; + headerElement: WebElementWrapper; + cellElements: WebElementWrapper[]; + cellContentElements: WebElementWrapper[]; + getSortDirection: () => Promise<'ascending' | 'descending' | undefined>; + sort: (sortDirection: 'ascending' | 'descending') => Promise; + getCellTexts: (selector?: string) => Promise; + getCellChildren: (selector: string) => Promise; + } + > = {}; + + for (let i = 0; i < headerElementWrappers.length; i++) { + const tdSelector = `table > tbody > tr td:nth-child(${i + 1})`; + const cellContentSelector = `${tdSelector} .euiTableCellContent`; + const thWrapper = headerElementWrappers[i]; + const columnName = await thWrapper.getVisibleText(); + const columnIndex = `${i}`; + const columnNameOrIndex = columnNamesOrIndexes.includes(columnName) + ? columnName + : columnNamesOrIndexes.includes(columnIndex) + ? columnIndex + : undefined; + + if (columnNameOrIndex) { + const headerElement = thWrapper; + + const tdWrappers = await tableWrapper.findAllByCssSelector(tdSelector); + const cellContentWrappers = await tableWrapper.findAllByCssSelector(cellContentSelector); + + const getSortDirection = () => + headerElement.getAttribute('aria-sort') as Promise< + 'ascending' | 'descending' | undefined + >; + + result[columnNameOrIndex] = { + columnNameOrIndex, + headerElement, + cellElements: tdWrappers, + cellContentElements: cellContentWrappers, + getSortDirection, + sort: async (sortDirection: 'ascending' | 'descending') => { + await retry.tryForTime(5000, async () => { + while ((await getSortDirection()) !== sortDirection) { + await headerElement.click(); + } + }); + }, + getCellTexts: async (textContainerSelector?: string) => { + const cellContentContainerWrappers = textContainerSelector + ? await tableWrapper.findAllByCssSelector(`${tdSelector} ${textContainerSelector}`) + : cellContentWrappers; + + const cellContentContainerWrapperTexts: string[] = []; + for (let j = 0; j < cellContentContainerWrappers.length; j++) { + const cellContentContainerWrapper = cellContentContainerWrappers[j]; + const cellContentContainerWrapperText = + await cellContentContainerWrapper.getVisibleText(); + cellContentContainerWrapperTexts.push(cellContentContainerWrapperText); + } + + return cellContentContainerWrapperTexts; + }, + getCellChildren: (childSelector: string) => { + return tableWrapper.findAllByCssSelector(`${cellContentSelector} ${childSelector}`); + }, + }; + } + } + + return result; + }, }; } @@ -440,86 +544,6 @@ async function getDatasetTableHeaderTexts(tableWrapper: WebElementWrapper) { ); } -async function parseDatasetTable(tableWrapper: WebElementWrapper, columnNamesOrIndexes: string[]) { - const headerElementWrappers = await tableWrapper.findAllByCssSelector('thead th, thead td'); - - const result: Record< - string, - { - columnNameOrIndex: string; - sortDirection?: 'ascending' | 'descending'; - headerElement: WebElementWrapper; - cellElements: WebElementWrapper[]; - cellContentElements: WebElementWrapper[]; - getSortDirection: () => Promise<'ascending' | 'descending' | undefined>; - sort: (sortDirection: 'ascending' | 'descending') => Promise; - getCellTexts: (selector?: string) => Promise; - getCellChildren: (selector: string) => Promise; - } - > = {}; - - for (let i = 0; i < headerElementWrappers.length; i++) { - const tdSelector = `table > tbody > tr td:nth-child(${i + 1})`; - const cellContentSelector = `${tdSelector} .euiTableCellContent`; - const thWrapper = headerElementWrappers[i]; - const columnName = await thWrapper.getVisibleText(); - const columnIndex = `${i}`; - const columnNameOrIndex = columnNamesOrIndexes.includes(columnName) - ? columnName - : columnNamesOrIndexes.includes(columnIndex) - ? columnIndex - : undefined; - - if (columnNameOrIndex) { - const headerElement = thWrapper; - - const tdWrappers = await tableWrapper.findAllByCssSelector(tdSelector); - const cellContentWrappers = await tableWrapper.findAllByCssSelector(cellContentSelector); - - const getSortDirection = () => - headerElement.getAttribute('aria-sort') as Promise<'ascending' | 'descending' | undefined>; - - result[columnNameOrIndex] = { - columnNameOrIndex, - headerElement, - cellElements: tdWrappers, - cellContentElements: cellContentWrappers, - getSortDirection, - sort: async (sortDirection: 'ascending' | 'descending') => { - if ((await getSortDirection()) !== sortDirection) { - await headerElement.click(); - } - - // Sorting twice if the sort was in neutral state - if ((await getSortDirection()) !== sortDirection) { - await headerElement.click(); - } - }, - getCellTexts: async (textContainerSelector?: string) => { - const cellContentContainerWrappers = textContainerSelector - ? await tableWrapper.findAllByCssSelector(`${tdSelector} ${textContainerSelector}`) - : cellContentWrappers; - - const cellContentContainerWrapperTexts: string[] = []; - for (let j = 0; j < cellContentContainerWrappers.length; j++) { - const cellContentContainerWrapper = cellContentContainerWrappers[j]; - const cellContentContainerWrapperText = - await cellContentContainerWrapper.getVisibleText(); - cellContentContainerWrapperTexts.push(cellContentContainerWrapperText); - } - - return cellContentContainerWrapperTexts; - }, - getCellChildren: (childSelector: string) => { - return tableWrapper.findAllByCssSelector(`${cellContentSelector} ${childSelector}`); - }, - }; - } - } - - return result; -} - /** * Get all elements matching the given selector and text * @example @@ -544,17 +568,3 @@ export async function getAllByText(container: WebElementWrapper, selector: strin return matchingElements; } - -const texts = { - noActivityText: 'No activity in the selected timeframe', - datasetHealthPoor: 'Poor', - datasetHealthDegraded: 'Degraded', - datasetHealthGood: 'Good', - activeDatasets: 'Active Data Sets', - estimatedData: 'Estimated Data', - docsCountTotal: 'Docs count (total)', - size: 'Size', - services: 'Services', - hosts: 'Hosts', - degradedDocs: 'Degraded docs', -}; diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/data/logs_data.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/data/logs_data.ts index 399030d1dd3770..168aeb4b4df211 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/data/logs_data.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/data/logs_data.ts @@ -191,6 +191,7 @@ export function createDegradedFieldsRecord({ export const datasetNames = ['synth.1', 'synth.2', 'synth.3']; export const defaultNamespace = 'default'; +export const productionNamespace = 'production'; // Logs Data logic const MESSAGE_LOG_LEVELS: MessageWithLevel[] = [ diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts index 0ca26b296fe130..24f6011c788553 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts @@ -12,6 +12,7 @@ import { getInitialTestLogs, getLogsForDataset, createDegradedFieldsRecord, + productionNamespace, } from './data'; const integrationActions = { @@ -36,25 +37,72 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const to = '2024-01-01T12:00:00.000Z'; const excludeKeysFromServerless = ['size']; // https://github.com/elastic/kibana/issues/178954 - describe('Dataset quality flyout', function () { - // FLAKY: https://github.com/elastic/kibana/issues/183771 - // Added this sub describe block so that the existing flaky tests can be skipped and new ones can be added in the other describe block - - describe.skip('Other dataset quality flyout tests', () => { - this.tags(['failsOnMKI']); // Failing https://github.com/elastic/kibana/issues/183495 - - before(async () => { - await PageObjects.svlCommonPage.loginWithRole('admin'); - await synthtrace.index(getInitialTestLogs({ to, count: 4 })); - await PageObjects.datasetQuality.navigateTo(); - }); + const apacheAccessDatasetName = 'apache.access'; + const apacheAccessDatasetHumanName = 'Apache access logs'; + const apacheIntegrationId = 'apache'; + const apachePkg = { + name: 'apache', + version: '1.14.0', + }; + + const bitbucketDatasetName = 'atlassian_bitbucket.audit'; + const bitbucketDatasetHumanName = 'Bitbucket Audit Logs'; + const bitbucketPkg = { + name: 'atlassian_bitbucket', + version: '1.14.0', + }; + + const degradedDatasetName = datasetNames[2]; + + describe('Flyout', function () { + before(async () => { + // Install Apache Integration and ingest logs for it + await PageObjects.observabilityLogsExplorer.installPackage(apachePkg); + + // Install Bitbucket Integration (package which does not has Dashboards) and ingest logs for it + await PageObjects.observabilityLogsExplorer.installPackage(bitbucketPkg); + + await synthtrace.index([ + // Ingest basic logs + getInitialTestLogs({ to, count: 4 }), + // Ingest Degraded Logs + createDegradedFieldsRecord({ + to: new Date().toISOString(), + count: 2, + dataset: degradedDatasetName, + }), + // Index 15 logs for `logs-apache.access` dataset + getLogsForDataset({ + to: new Date().toISOString(), + count: 15, + dataset: apacheAccessDatasetName, + namespace: productionNamespace, + }), + // Index degraded docs for Apache integration + getLogsForDataset({ + to: new Date().toISOString(), + count: 1, + dataset: apacheAccessDatasetName, + namespace: productionNamespace, + isMalformed: true, + }), + // Index logs for Bitbucket integration + getLogsForDataset({ to, count: 10, dataset: bitbucketDatasetName }), + ]); + + await PageObjects.svlCommonPage.loginWithRole('admin'); + + await PageObjects.datasetQuality.navigateTo(); + }); - after(async () => { - await synthtrace.clean(); - await PageObjects.observabilityLogsExplorer.removeInstalledPackages(); - }); + after(async () => { + await PageObjects.observabilityLogsExplorer.uninstallPackage(apachePkg); + await PageObjects.observabilityLogsExplorer.uninstallPackage(bitbucketPkg); + await synthtrace.clean(); + }); - it('opens the flyout for the right dataset', async () => { + describe('open flyout', () => { + it('should open the flyout for the right dataset', async () => { const testDatasetName = datasetNames[1]; await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); @@ -62,44 +110,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.existOrFail( PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutTitle ); - }); - // Fails on Serverless. TODO: Need to update the UI as well as the test - it.skip('shows the correct last activity', async () => { - const testDatasetName = datasetNames[0]; - - // Update last activity for the dataset await PageObjects.datasetQuality.closeFlyout(); - await synthtrace.index( - getLogsForDataset({ to: new Date().toISOString(), count: 1, dataset: testDatasetName }) - ); - await PageObjects.datasetQuality.refreshTable(); - - const cols = await PageObjects.datasetQuality.parseDatasetTable(); - - const datasetNameCol = cols['Data Set Name']; - const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - - const testDatasetRowIndex = datasetNameColCellTexts.findIndex( - (dName: string) => dName === testDatasetName - ); - - const lastActivityText = (await cols['Last Activity'].getCellTexts())[testDatasetRowIndex]; - - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); - - const lastActivityTextExists = await PageObjects.datasetQuality.doestTextExistInFlyout( - lastActivityText, - `[data-test-subj=${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutFieldValue}]` - ); - - expect(lastActivityTextExists).to.eql(true); }); - // FLAKY: https://github.com/elastic/kibana/issues/180994 - it.skip('reflects the breakdown field state in url', async () => { - const testDatasetName = datasetNames[0]; - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + it('reflects the breakdown field state in url', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); const breakdownField = 'service.name'; await PageObjects.datasetQuality.selectBreakdownField(breakdownField); @@ -118,25 +134,25 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const currentUrl = await browser.getCurrentUrl(); expect(currentUrl).to.not.contain('breakdownField'); }); + await PageObjects.datasetQuality.closeFlyout(); }); + }); - it('shows the integration details', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - const apacheIntegrationId = 'apache'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); + describe('integrations', () => { + it('should hide the integration section for non integrations', async () => { + const testDatasetName = datasetNames[1]; - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); + await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) + await testSubjects.missingOrFail( + PageObjects.datasetQuality.testSubjectSelectors + .datasetQualityFlyoutFieldsListIntegrationDetails ); - await PageObjects.datasetQuality.navigateTo(); + await PageObjects.datasetQuality.closeFlyout(); + }); + it('should shows the integration section for integrations', async () => { await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); const integrationNameElements = await PageObjects.datasetQuality.getFlyoutElementsByText( @@ -144,134 +160,140 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { apacheIntegrationId ); - await PageObjects.datasetQuality.closeFlyout(); + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors + .datasetQualityFlyoutFieldsListIntegrationDetails + ); expect(integrationNameElements.length).to.eql(1); + + await PageObjects.datasetQuality.closeFlyout(); }); - it('goes to log explorer page when open button is clicked', async () => { - const testDatasetName = datasetNames[2]; - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + it('should show the integration actions menu with correct actions', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); - await (await PageObjects.datasetQuality.getFlyoutLogsExplorerButton()).click(); + const actions = await Promise.all( + Object.values(integrationActions).map((action) => + PageObjects.datasetQuality.getIntegrationActionButtonByAction(action) + ) + ); - // Confirm dataset selector text in observability logs explorer - const datasetSelectorText = - await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); - expect(datasetSelectorText).to.eql(testDatasetName); + expect(actions.length).to.eql(3); + await PageObjects.datasetQuality.closeFlyout(); }); - it('shows summary KPIs', async () => { - await PageObjects.datasetQuality.navigateTo(); + it('should hide integration dashboard for integrations without dashboards', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); - const apacheAccessDatasetHumanName = 'Apache access logs'; - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await testSubjects.missingOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction( + integrationActions.viewDashboards + ) + ); + await PageObjects.datasetQuality.closeFlyout(); + }); + + it('Should navigate to integration overview page on clicking integration overview action', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); - const summary = await PageObjects.datasetQuality.parseFlyoutKpis(excludeKeysFromServerless); - expect(summary).to.eql({ - docsCountTotal: '0', - // size: '0.0 B', // `_stats` not available on Serverless - services: '0', - hosts: '0', - degradedDocs: '0', + const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( + integrationActions.overview + ); + + await action.click(); + + await retry.tryForTime(5000, async () => { + const currentUrl = await browser.getCurrentUrl(); + const parsedUrl = new URL(currentUrl); + + expect(parsedUrl.pathname).to.contain('/app/integrations/detail/atlassian_bitbucket'); }); + + await PageObjects.datasetQuality.navigateTo(); }); - it('shows the updated KPIs', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; + it('should navigate to index template page in clicking Integration template', async () => { await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); - const summaryBefore = await PageObjects.datasetQuality.parseFlyoutKpis( - excludeKeysFromServerless + const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( + integrationActions.template ); - // Set time range to 3 days ago - const flyoutBodyContainer = await testSubjects.find( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutBody - ); - await PageObjects.datasetQuality.setDatePickerLastXUnits(flyoutBodyContainer, 3, 'd'); + await action.click(); - // Index 2 doc 2 days ago - const time2DaysAgo = Date.now() - 2 * 24 * 60 * 60 * 1000; - await synthtrace.index( - getLogsForDataset({ - to: time2DaysAgo, - count: 2, - dataset: apacheAccessDatasetName, - isMalformed: false, - }) - ); + await retry.tryForTime(5000, async () => { + const currentUrl = await browser.getCurrentUrl(); + const parsedUrl = new URL(currentUrl); + expect(parsedUrl.pathname).to.contain( + `/app/management/data/index_management/templates/logs-${apacheAccessDatasetName}` + ); + }); + await PageObjects.datasetQuality.navigateTo(); + }); - // Index 5 degraded docs 2 days ago - await synthtrace.index( - getLogsForDataset({ - to: time2DaysAgo, - count: 5, - dataset: apacheAccessDatasetName, - isMalformed: true, - }) - ); + it('should navigate to the selected dashboard on clicking integration dashboard action ', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); - await PageObjects.datasetQuality.refreshFlyout(); - const summaryAfter = await PageObjects.datasetQuality.parseFlyoutKpis( - excludeKeysFromServerless + const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( + integrationActions.viewDashboards ); - expect(parseInt(summaryAfter.docsCountTotal, 10)).to.be.greaterThan( - parseInt(summaryBefore.docsCountTotal, 10) - ); + await action.click(); - expect(parseInt(summaryAfter.degradedDocs, 10)).to.be.greaterThan( - parseInt(summaryBefore.degradedDocs, 10) - ); + const dashboardButtons = await PageObjects.datasetQuality.getIntegrationDashboardButtons(); + const firstDashboardButton = await dashboardButtons[0]; + const dashboardText = await firstDashboardButton.getVisibleText(); - // `_stats` not available on Serverless so we can't compare size // https://github.com/elastic/kibana/issues/178954 - // expect(parseInt(summaryAfter.size, 10)).to.be.greaterThan(parseInt(summaryBefore.size, 10)); + await firstDashboardButton.click(); - expect(parseInt(summaryAfter.services, 10)).to.be.greaterThan( - parseInt(summaryBefore.services, 10) - ); - expect(parseInt(summaryAfter.hosts, 10)).to.be.greaterThan( - parseInt(summaryBefore.hosts, 10) - ); + const breadcrumbText = await testSubjects.getVisibleText('breadcrumb last'); + + expect(breadcrumbText).to.eql(dashboardText); + + await PageObjects.datasetQuality.navigateTo(); }); + }); - it('shows the right number of services', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; + describe('summary panel', () => { + it('should show summary KPIs', async () => { await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - const summaryBefore = await PageObjects.datasetQuality.parseFlyoutKpis( - excludeKeysFromServerless - ); - const testServices = ['test-srv-1', 'test-srv-2']; + const { docsCountTotal, degradedDocs, services, hosts } = + await PageObjects.datasetQuality.parseFlyoutKpis(excludeKeysFromServerless); + expect(parseInt(docsCountTotal, 10)).to.be(226); + expect(parseInt(degradedDocs, 10)).to.be(1); + expect(parseInt(services, 10)).to.be(3); + expect(parseInt(hosts, 10)).to.be(52); - // Index 2 docs with different services - const timeNow = Date.now(); - await synthtrace.index( - getLogsForDataset({ - to: timeNow, - count: 2, - dataset: apacheAccessDatasetName, - isMalformed: false, - services: testServices, - }) - ); + await PageObjects.datasetQuality.closeFlyout(); + }); + }); - await PageObjects.datasetQuality.refreshFlyout(); - const summaryAfter = await PageObjects.datasetQuality.parseFlyoutKpis( - excludeKeysFromServerless - ); + describe('navigation', () => { + it('should go to log explorer page when the open in log explorer button is clicked', async () => { + const testDatasetName = datasetNames[2]; + await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); - expect(parseInt(summaryAfter.services, 10)).to.eql( - parseInt(summaryBefore.services, 10) + testServices.length - ); + const logExplorerButton = await PageObjects.datasetQuality.getFlyoutLogsExplorerButton(); + + await logExplorerButton.click(); + + // Confirm dataset selector text in observability logs explorer + const datasetSelectorText = + await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); + expect(datasetSelectorText).to.eql(testDatasetName); + + // Should bring back the test to the dataset quality page + await PageObjects.datasetQuality.navigateTo(); }); - it('goes to log explorer for degraded docs when show all is clicked', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; + it('should go log explorer for degraded docs when the show all button is clicked', async () => { await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); const degradedDocsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.degradedDocs}`; @@ -285,11 +307,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.closeCurrentWindow(); await browser.switchTab(0); + + await PageObjects.datasetQuality.closeFlyout(); }); // Blocked by https://github.com/elastic/kibana/issues/181705 + // Its a test written ahead of its time. it.skip('goes to infra hosts for hosts when show all is clicked', async () => { - const apacheAccessDatasetHumanName = 'Apache access logs'; await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); const hostsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.hosts}`; @@ -305,308 +329,132 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.closeCurrentWindow(); await browser.switchTab(0); - }); - - it('Integration actions menu is present with correct actions', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - await PageObjects.observabilityLogsExplorer.navigateTo(); + await PageObjects.datasetQuality.closeFlyout(); + }); + }); - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); + describe('degraded fields table', () => { + it(' should show empty degraded fields table when no degraded fields are present', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(datasetNames[0]); - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedTableNoData ); - await PageObjects.datasetQuality.navigateTo(); + await PageObjects.datasetQuality.closeFlyout(); + }); - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); + it('should show the degraded fields table with data when present', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - const actions = await Promise.all( - Object.values(integrationActions).map((action) => - PageObjects.datasetQuality.getIntegrationActionButtonByAction(action) - ) + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable ); - expect(actions.length).to.eql(3); - }); + const rows = + await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); - it('Integration dashboard action hidden for integrations without dashboards', async () => { - const bitbucketDatasetName = 'atlassian_bitbucket.audit'; - const bitbucketDatasetHumanName = 'Bitbucket Audit Logs'; + expect(rows.length).to.eql(2); - await PageObjects.observabilityLogsExplorer.navigateTo(); + await PageObjects.datasetQuality.closeFlyout(); + }); - // Add initial integrations - await PageObjects.observabilityLogsExplorer.installPackage({ - name: 'atlassian_bitbucket', - version: '1.14.0', - }); + it('should display Spark Plot for every row of degraded fields', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - // Index 10 logs for `atlassian_bitbucket.audit` dataset - await synthtrace.index(getLogsForDataset({ to, count: 10, dataset: bitbucketDatasetName })); + const rows = + await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); - await PageObjects.datasetQuality.navigateTo(); + const sparkPlots = await testSubjects.findAll( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot + ); - await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); + expect(rows.length).to.be(sparkPlots.length); - await testSubjects.missingOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction( - integrationActions.viewDashboards - ) - ); + await PageObjects.datasetQuality.closeFlyout(); }); - it('Integration overview action should navigate to the integration overview page', async () => { - const bitbucketDatasetName = 'atlassian_bitbucket.audit'; - const bitbucketDatasetHumanName = 'Bitbucket Audit Logs'; + it('should sort the table when the count table header is clicked', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - await PageObjects.observabilityLogsExplorer.navigateTo(); + const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); - // Add initial integrations - await PageObjects.observabilityLogsExplorer.installPackage({ - name: 'atlassian_bitbucket', - version: '1.14.0', - }); + const countColumn = table['Docs count']; + const cellTexts = await countColumn.getCellTexts(); - // Index 10 logs for `atlassian_bitbucket.audit` dataset - await synthtrace.index(getLogsForDataset({ to, count: 10, dataset: bitbucketDatasetName })); + await countColumn.sort('ascending'); + const sortedCellTexts = await countColumn.getCellTexts(); - await PageObjects.datasetQuality.navigateTo(); + expect(cellTexts.reverse()).to.eql(sortedCellTexts); - await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); + await PageObjects.datasetQuality.closeFlyout(); + }); - const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( - integrationActions.overview - ); + it('should update the URL when the table is sorted', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - await action.click(); + const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); + const countColumn = table['Docs count']; await retry.tryForTime(5000, async () => { const currentUrl = await browser.getCurrentUrl(); const parsedUrl = new URL(currentUrl); + const pageState = parsedUrl.searchParams.get('pageState'); - expect(parsedUrl.pathname).to.contain('/app/integrations/detail/atlassian_bitbucket'); + expect(decodeURIComponent(pageState as string)).to.contain( + 'sort:(direction:desc,field:count)' + ); }); - }); - - it('Integration template action should navigate to the index template page', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) - ); - - await PageObjects.datasetQuality.navigateTo(); - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); + countColumn.sort('ascending'); await retry.tryForTime(5000, async () => { - const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( - integrationActions.template - ); - - await action.click(); - const currentUrl = await browser.getCurrentUrl(); const parsedUrl = new URL(currentUrl); - expect(parsedUrl.pathname).to.contain( - `/app/management/data/index_management/templates/logs-${apacheAccessDatasetName}` - ); - }); - }); - - it('Integration dashboard action should navigate to the selected dashboard', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) - ); - - await PageObjects.datasetQuality.navigateTo(); - - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - await PageObjects.datasetQuality.openIntegrationActionsMenu(); - - const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( - integrationActions.viewDashboards - ); - - await action.click(); - - const dashboardButtons = await PageObjects.datasetQuality.getIntegrationDashboardButtons(); - const firstDashboardButton = await dashboardButtons[0]; - const dashboardText = await firstDashboardButton.getVisibleText(); - - await firstDashboardButton.click(); - - const breadcrumbText = await testSubjects.getVisibleText('breadcrumb last'); - - expect(breadcrumbText).to.eql(dashboardText); - }); - }); + const pageState = parsedUrl.searchParams.get('pageState'); - // The above describe block has some failing/flaky tests which will - // be fixed as part of the tech debt mentioned here - // https://github.com/elastic/kibana/issues/184145 - // Until then, the below describe block is added to cover the tests for the - // newly added degraded Fields Table. This must be merged under the above - // describe block once the tech debt is fixed. - // - // FLAKY: https://github.com/elastic/kibana/issues/184438 - describe.skip('Dataset quality flyout with degraded fields', () => { - const goodDatasetName = 'good'; - const degradedDatasetName = 'degraded'; - const today = new Date().toISOString(); - describe('Degraded Fields Table with common data', () => { - before(async () => { - await PageObjects.svlCommonPage.loginWithRole('admin'); - await synthtrace.index([ - getLogsForDataset({ - to: today, - count: 2, - dataset: goodDatasetName, - isMalformed: false, - }), - createDegradedFieldsRecord({ - to: today, - count: 2, - dataset: degradedDatasetName, - }), - ]); - await PageObjects.datasetQuality.navigateTo(); - }); - - after(async () => { - await synthtrace.clean(); - }); - it('shows the degraded fields table with no data when no degraded fields are present', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(goodDatasetName); - - await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedTableNoData - ); - - await PageObjects.datasetQuality.closeFlyout(); - }); - - it('should load the degraded fields table with data', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - - await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable + expect(decodeURIComponent(pageState as string)).to.contain( + 'sort:(direction:asc,field:count)' ); - - const rows = - await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); - - expect(rows.length).to.eql(2); - - await PageObjects.datasetQuality.closeFlyout(); }); - it('should display Spark Plot for every row of degraded fields', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - - const rows = - await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); - - const sparkPlots = await testSubjects.findAll( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot - ); - - expect(rows.length).to.be(sparkPlots.length); - - await PageObjects.datasetQuality.closeFlyout(); - }); - - it('should sort the table when the count table header is clicked', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - - const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); - - const countColumn = table['Docs count']; - const cellTexts = await countColumn.getCellTexts(); - - await countColumn.sort('ascending'); - const sortedCellTexts = await countColumn.getCellTexts(); - - expect(cellTexts.reverse()).to.eql(sortedCellTexts); - - await PageObjects.datasetQuality.closeFlyout(); - }); + await PageObjects.datasetQuality.closeFlyout(); }); - describe('Degraded Fields Table with data ingestion', () => { - before(async () => { - await PageObjects.svlCommonPage.loginWithRole('admin'); - await synthtrace.index([ - getLogsForDataset({ - to: today, - count: 2, - dataset: goodDatasetName, - isMalformed: false, - }), - createDegradedFieldsRecord({ - to: today, - count: 2, - dataset: degradedDatasetName, - }), - ]); - await PageObjects.datasetQuality.navigateTo(); - }); + // This is the only test which ingest data during the test. + // This block tests the refresh behavior of the degraded fields table. + // Even though this test ingest data, it can also be freely moved inside + // this describe block, and it won't affect any of the existing tests + it('should update the table when new data is ingested and the flyout is refreshed using the time selector', async () => { + await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); - after(async () => { - await synthtrace.clean(); - }); - it('should update the table when new data is ingested and the flyout is refreshed using the time selector', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); - const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); + const countColumn = table['Docs count']; + const cellTexts = await countColumn.getCellTexts(); - const countColumn = table['Docs count']; - const cellTexts = await countColumn.getCellTexts(); - const singleValuePreviously = parseInt(cellTexts[0], 10); + await synthtrace.index([ + createDegradedFieldsRecord({ + to: new Date().toISOString(), + count: 2, + dataset: degradedDatasetName, + }), + ]); - await synthtrace.index([ - createDegradedFieldsRecord({ - to: today, - count: 2, - dataset: degradedDatasetName, - }), - ]); + await PageObjects.datasetQuality.refreshFlyout(); - await PageObjects.datasetQuality.refreshFlyout(); + const updatedTable = await PageObjects.datasetQuality.parseDegradedFieldTable(); + const updatedCountColumn = updatedTable['Docs count']; - const updatedCellTexts = await countColumn.getCellTexts(); + const updatedCellTexts = await updatedCountColumn.getCellTexts(); - const singleValueNow = parseInt(updatedCellTexts[0], 10); + const singleValuePreviously = parseInt(cellTexts[0], 10); + const singleValueNow = parseInt(updatedCellTexts[0], 10); - expect(singleValueNow).to.be(singleValuePreviously * 2); + expect(singleValueNow).to.be.greaterThan(singleValuePreviously); - await PageObjects.datasetQuality.closeFlyout(); - }); + await PageObjects.datasetQuality.closeFlyout(); }); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_summary.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_summary.ts index f5a6fd31a25f3b..5821612c0b9b21 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_summary.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_summary.ts @@ -17,11 +17,37 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'svlCommonPage', ]); const synthtrace = getService('svlLogsSynthtraceClient'); - const browser = getService('browser'); - const retry = getService('retry'); const to = '2024-01-01T12:00:00.000Z'; const excludeKeysFromServerless = ['estimatedData']; // https://github.com/elastic/kibana/issues/178954 + const ingestDataForSummary = async () => { + // Ingest documents for 3 type of datasets + return synthtrace.index([ + // Ingest good data to all 3 datasets + getInitialTestLogs({ to, count: 4 }), + // Ingesting poor data to one dataset + getLogsForDataset({ + to: Date.now(), + count: 1, + dataset: datasetNames[1], + isMalformed: true, + }), + // Ingesting degraded docs into another dataset by ingesting malformed 1st and then good data + getLogsForDataset({ + to: Date.now(), + count: 1, + dataset: datasetNames[2], + isMalformed: true, + }), + getLogsForDataset({ + to: Date.now(), + count: 10, + dataset: datasetNames[2], + isMalformed: false, + }), + ]); + }; + describe('Dataset quality summary', () => { before(async () => { await synthtrace.index(getInitialTestLogs({ to, count: 4 })); @@ -29,110 +55,31 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.datasetQuality.navigateTo(); }); - after(async () => { + afterEach(async () => { await synthtrace.clean(); }); - it('shows poor, degraded and good count', async () => { + it('shows poor, degraded and good count as 0 and all dataset as healthy', async () => { + await PageObjects.datasetQuality.refreshTable(); const summary = await PageObjects.datasetQuality.parseSummaryPanel(excludeKeysFromServerless); expect(summary).to.eql({ datasetHealthPoor: '0', datasetHealthDegraded: '0', datasetHealthGood: '3', activeDatasets: '0 of 3', - // estimatedData: '0.0 B', https://github.com/elastic/kibana/issues/178954 - }); - }); - - it('updates the poor count when degraded docs are ingested', async () => { - // Index malformed document with current timestamp - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 1, - dataset: datasetNames[2], - isMalformed: true, - }) - ); - - await browser.refresh(); - await PageObjects.datasetQuality.waitUntilSummaryPanelLoaded(); - - await retry.try(async () => { - const summary = await PageObjects.datasetQuality.parseSummaryPanel( - excludeKeysFromServerless - ); - const { estimatedData, ...restOfSummary } = summary; - expect(restOfSummary).to.eql({ - datasetHealthPoor: '1', - datasetHealthDegraded: '0', - datasetHealthGood: '2', - activeDatasets: '1 of 3', - }); - }); - }); - - it('updates the degraded count when degraded docs are ingested', async () => { - // Index malformed document with current timestamp - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 1, - dataset: datasetNames[1], - isMalformed: true, - }) - ); - - // Index healthy documents - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 10, - dataset: datasetNames[1], - isMalformed: false, - }) - ); - - await browser.refresh(); - await PageObjects.datasetQuality.waitUntilSummaryPanelLoaded(); - - await retry.try(async () => { - const { estimatedData, ...restOfSummary } = - await PageObjects.datasetQuality.parseSummaryPanel(excludeKeysFromServerless); - expect(restOfSummary).to.eql({ - datasetHealthPoor: '1', - datasetHealthDegraded: '1', - datasetHealthGood: '1', - activeDatasets: '2 of 3', - }); }); }); - it('updates active datasets and estimated data KPIs', async () => { - const { estimatedData: _existingEstimatedData } = - await PageObjects.datasetQuality.parseSummaryPanel(excludeKeysFromServerless); - - // Index document at current time to mark dataset as active - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 4, - dataset: datasetNames[0], - isMalformed: false, - }) - ); - - await browser.refresh(); // Summary panel doesn't update reactively - await PageObjects.datasetQuality.waitUntilSummaryPanelLoaded(); + it('shows updated count for poor, degraded and good datasets and updates active datasets', async () => { + await ingestDataForSummary(); + await PageObjects.datasetQuality.refreshTable(); - await retry.try(async () => { - const { activeDatasets: updatedActiveDatasets, estimatedData: _updatedEstimatedData } = - await PageObjects.datasetQuality.parseSummaryPanel(excludeKeysFromServerless); - - expect(updatedActiveDatasets).to.eql('3 of 3'); - - // TODO: `_stats` not available on Serverless. // https://github.com/elastic/kibana/issues/178954 - // expect(_updatedEstimatedData).to.not.eql(_existingEstimatedData); + const summary = await PageObjects.datasetQuality.parseSummaryPanel(excludeKeysFromServerless); + expect(summary).to.eql({ + datasetHealthPoor: '1', + datasetHealthDegraded: '1', + datasetHealthGood: '1', + activeDatasets: '2 of 3', }); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_table.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_table.ts index b86bf82a6266a4..40531e4b04d180 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_table.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_table.ts @@ -7,7 +7,13 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { datasetNames, defaultNamespace, getInitialTestLogs, getLogsForDataset } from './data'; +import { + datasetNames, + defaultNamespace, + getInitialTestLogs, + getLogsForDataset, + productionNamespace, +} from './data'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects([ @@ -19,42 +25,79 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'svlCommonPage', ]); const synthtrace = getService('svlLogsSynthtraceClient'); - const testSubjects = getService('testSubjects'); - const retry = getService('retry'); const to = '2024-01-01T12:00:00.000Z'; + const apacheAccessDatasetName = 'apache.access'; + const apacheAccessDatasetHumanName = 'Apache access logs'; + const pkg = { + name: 'apache', + version: '1.14.0', + }; describe('Dataset quality table', function () { - this.tags(['failsOnMKI']); // Failing https://github.com/elastic/kibana/issues/183495 - before(async () => { - await synthtrace.index(getInitialTestLogs({ to, count: 4 })); + // Install Integration and ingest logs for it + await PageObjects.observabilityLogsExplorer.installPackage(pkg); + // Ingest basic logs + await synthtrace.index([ + // Ingest basic logs + getInitialTestLogs({ to, count: 4 }), + // Ingest Degraded Logs + getLogsForDataset({ + to: new Date().toISOString(), + count: 1, + dataset: datasetNames[2], + isMalformed: true, + }), + // Index 10 logs for `logs-apache.access` dataset + getLogsForDataset({ + to, + count: 10, + dataset: apacheAccessDatasetName, + namespace: productionNamespace, + }), + ]); await PageObjects.svlCommonPage.loginWithRole('admin'); await PageObjects.datasetQuality.navigateTo(); }); after(async () => { await synthtrace.clean(); - await PageObjects.observabilityLogsExplorer.removeInstalledPackages(); + await PageObjects.observabilityLogsExplorer.uninstallPackage(pkg); }); - it('shows the right number of rows in correct order', async () => { + it('shows sort by dataset name and show namespace', async () => { const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; await datasetNameCol.sort('descending'); const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTexts).to.eql([...datasetNames].reverse()); + expect(datasetNameColCellTexts).to.eql( + [apacheAccessDatasetHumanName, ...datasetNames].reverse() + ); const namespaceCol = cols.Namespace; const namespaceColCellTexts = await namespaceCol.getCellTexts(); - expect(namespaceColCellTexts).to.eql([defaultNamespace, defaultNamespace, defaultNamespace]); + expect(namespaceColCellTexts).to.eql([ + defaultNamespace, + defaultNamespace, + defaultNamespace, + productionNamespace, + ]); - const degradedDocsCol = cols['Degraded Docs (%)']; - const degradedDocsColCellTexts = await degradedDocsCol.getCellTexts(); - expect(degradedDocsColCellTexts).to.eql(['0%', '0%', '0%']); + // Cleaning the sort + await datasetNameCol.sort('ascending'); + }); + it('shows the last activity', async () => { + const cols = await PageObjects.datasetQuality.parseDatasetTable(); const lastActivityCol = cols['Last Activity']; - const lastActivityColCellTexts = await lastActivityCol.getCellTexts(); - expect(lastActivityColCellTexts).to.eql([ + const activityCells = await lastActivityCol.getCellTexts(); + const lastActivityCell = activityCells[activityCells.length - 1]; + const restActivityCells = activityCells.slice(0, -1); + + // The first cell of lastActivity should have data + expect(lastActivityCell).to.not.eql(PageObjects.datasetQuality.texts.noActivityText); + // The rest of the rows must show no activity + expect(restActivityCells).to.eql([ PageObjects.datasetQuality.texts.noActivityText, PageObjects.datasetQuality.texts.noActivityText, PageObjects.datasetQuality.texts.noActivityText, @@ -63,112 +106,19 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('shows degraded docs percentage', async () => { const cols = await PageObjects.datasetQuality.parseDatasetTable(); - const datasetNameCol = cols['Data Set Name']; - await datasetNameCol.sort('ascending'); const degradedDocsCol = cols['Degraded Docs (%)']; const degradedDocsColCellTexts = await degradedDocsCol.getCellTexts(); - expect(degradedDocsColCellTexts).to.eql(['0%', '0%', '0%']); - - // Index malformed document with current timestamp - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 1, - dataset: datasetNames[2], - isMalformed: true, - }) - ); - - // Set time range to Last 5 minute - const filtersContainer = await testSubjects.find( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFiltersContainer - ); - await PageObjects.datasetQuality.setDatePickerLastXUnits(filtersContainer, 5, 'm'); - - const updatedDegradedDocsColCellTexts = await degradedDocsCol.getCellTexts(); - expect(updatedDegradedDocsColCellTexts[2]).to.not.eql('0%'); - }); - - // https://github.com/elastic/kibana/issues/178954 - it.skip('shows the updated size of the index', async () => { - const testDatasetIndex = 2; - const cols = await PageObjects.datasetQuality.parseDatasetTable(); - const datasetNameCol = cols['Data Set Name']; - await datasetNameCol.sort('ascending'); - const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - - const datasetToUpdateRowIndex = datasetNameColCellTexts.findIndex( - (dName: string) => dName === datasetNames[testDatasetIndex] - ); - - const sizeColCellTexts = await cols.Size.getCellTexts(); - const beforeSize = sizeColCellTexts[datasetToUpdateRowIndex]; - - // Index documents with current timestamp - await synthtrace.index( - getLogsForDataset({ - to: Date.now(), - count: 4, - dataset: datasetNames[testDatasetIndex], - isMalformed: false, - }) - ); - - const colsAfterUpdate = await PageObjects.datasetQuality.parseDatasetTable(); - - // Assert that size has changed - await retry.tryForTime(15000, async () => { - // Refresh the table - await PageObjects.datasetQuality.refreshTable(); - const updatedSizeColCellTexts = await colsAfterUpdate.Size.getCellTexts(); - expect(updatedSizeColCellTexts[datasetToUpdateRowIndex]).to.not.eql(beforeSize); - }); - }); - - it('sorts by dataset name', async () => { - // const header = await PageObjects.datasetQuality.getDatasetTableHeader('Dataset Name'); - const cols = await PageObjects.datasetQuality.parseDatasetTable(); - const datasetNameCol = cols['Data Set Name']; - - // Sort ascending - await datasetNameCol.sort('ascending'); - const cellTexts = await datasetNameCol.getCellTexts(); - - const datasetNamesAsc = [...datasetNames].sort(); - - expect(cellTexts).to.eql(datasetNamesAsc); + expect(degradedDocsColCellTexts).to.eql(['0%', '0%', '0%', '100%']); }); it('shows dataset from integration', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) - ); - - await PageObjects.datasetQuality.navigateTo(); - const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; - // Sort ascending - await datasetNameCol.sort('ascending'); const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - const datasetNamesAsc = [...datasetNames, apacheAccessDatasetHumanName].sort(); - - // Assert there are 4 rows - expect(datasetNameColCellTexts.length).to.eql(4); - - expect(datasetNameColCellTexts).to.eql(datasetNamesAsc); + expect(datasetNameColCellTexts[0]).to.eql(apacheAccessDatasetHumanName); }); it('goes to log explorer page when opened', async () => { @@ -184,50 +134,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const datasetSelectorText = await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); expect(datasetSelectorText).to.eql(datasetName); - }); - it('shows the last activity when in time range', async () => { + // Return to Dataset Quality Page await PageObjects.datasetQuality.navigateTo(); - const cols = await PageObjects.datasetQuality.parseDatasetTable(); - const lastActivityCol = cols['Last Activity']; - const datasetNameCol = cols['Data Set Name']; - - // Set time range to Last 1 minute - const filtersContainer = await testSubjects.find( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFiltersContainer - ); - - await PageObjects.datasetQuality.setDatePickerLastXUnits(filtersContainer, 1, 's'); - const lastActivityColCellTexts = await lastActivityCol.getCellTexts(); - expect(lastActivityColCellTexts).to.eql([ - PageObjects.datasetQuality.texts.noActivityText, - PageObjects.datasetQuality.texts.noActivityText, - PageObjects.datasetQuality.texts.noActivityText, - PageObjects.datasetQuality.texts.noActivityText, - ]); - - const datasetToUpdate = datasetNames[0]; - await synthtrace.index( - getLogsForDataset({ to: new Date().toISOString(), count: 1, dataset: datasetToUpdate }) - ); - const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - const datasetToUpdateRowIndex = datasetNameColCellTexts.findIndex( - (dName: string) => dName === datasetToUpdate - ); - - await PageObjects.datasetQuality.setDatePickerLastXUnits(filtersContainer, 1, 'h'); - - await retry.tryForTime(5000, async () => { - const updatedLastActivityColCellTexts = await lastActivityCol.getCellTexts(); - expect(updatedLastActivityColCellTexts[datasetToUpdateRowIndex]).to.not.eql( - PageObjects.datasetQuality.texts.noActivityText - ); - }); }); it('hides inactive datasets', async () => { - await PageObjects.datasetQuality.waitUntilTableLoaded(); - // Get number of rows with Last Activity not equal to "No activity in the selected timeframe" const cols = await PageObjects.datasetQuality.parseDatasetTable(); const lastActivityCol = cols['Last Activity']; diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_table_filters.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_table_filters.ts index 239e4322876b05..b53ffe313e86ec 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_table_filters.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_table_filters.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { datasetNames, defaultNamespace, getInitialTestLogs, getLogsForDataset } from './data'; +import { datasetNames, getInitialTestLogs, getLogsForDataset, productionNamespace } from './data'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects([ @@ -20,58 +20,73 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const synthtrace = getService('svlLogsSynthtraceClient'); const testSubjects = getService('testSubjects'); const to = '2024-01-01T12:00:00.000Z'; + const apacheAccessDatasetName = 'apache.access'; + const apacheAccessDatasetHumanName = 'Apache access logs'; + const apacheIntegrationName = 'Apache HTTP Server'; + const pkg = { + name: 'apache', + version: '1.14.0', + }; + const allDatasetNames = [apacheAccessDatasetHumanName, ...datasetNames]; describe('Dataset quality table filters', function () { - this.tags(['failsOnMKI']); // Failing https://github.com/elastic/kibana/issues/183495 - before(async () => { - await synthtrace.index(getInitialTestLogs({ to, count: 4 })); + // Install Integration and ingest logs for it + await PageObjects.observabilityLogsExplorer.installPackage(pkg); + // Ingest basic logs + await synthtrace.index([ + // Ingest basic logs + getInitialTestLogs({ to, count: 4 }), + // Ingest Degraded Logs + getLogsForDataset({ + to: new Date().toISOString(), + count: 1, + dataset: datasetNames[2], + isMalformed: true, + }), + // Index 10 logs for `logs-apache.access` dataset + getLogsForDataset({ + to, + count: 10, + dataset: apacheAccessDatasetName, + namespace: productionNamespace, + }), + ]); await PageObjects.svlCommonPage.loginWithRole('admin'); await PageObjects.datasetQuality.navigateTo(); }); after(async () => { + await PageObjects.observabilityLogsExplorer.uninstallPackage(pkg); await synthtrace.clean(); - await PageObjects.observabilityLogsExplorer.removeInstalledPackages(); - }); - - it('hides inactive datasets when toggled', async () => { - const initialRows = await PageObjects.datasetQuality.getDatasetTableRows(); - expect(initialRows.length).to.eql(3); - - await PageObjects.datasetQuality.toggleShowInactiveDatasets(); - - const afterToggleRows = await PageObjects.datasetQuality.getDatasetTableRows(); - expect(afterToggleRows.length).to.eql(1); - - await PageObjects.datasetQuality.toggleShowInactiveDatasets(); - - const afterReToggleRows = await PageObjects.datasetQuality.getDatasetTableRows(); - expect(afterReToggleRows.length).to.eql(3); }); it('shows full dataset names when toggled', async () => { const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTexts).to.eql(datasetNames); + expect(datasetNameColCellTexts).to.eql(allDatasetNames); await PageObjects.datasetQuality.toggleShowFullDatasetNames(); const datasetNameColCellTextsAfterToggle = await datasetNameCol.getCellTexts(); - const duplicateNames = datasetNames.map((name) => `${name}\n${name}`); + const duplicateNames = [ + `${apacheAccessDatasetHumanName}\n${apacheAccessDatasetName}`, + ...datasetNames.map((name) => `${name}\n${name}`), + ]; expect(datasetNameColCellTextsAfterToggle).to.eql(duplicateNames); + // resetting the toggle await PageObjects.datasetQuality.toggleShowFullDatasetNames(); const datasetNameColCellTextsAfterReToggle = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTextsAfterReToggle).to.eql(datasetNames); + expect(datasetNameColCellTextsAfterReToggle).to.eql(allDatasetNames); }); it('searches the datasets', async () => { const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTexts).to.eql(datasetNames); + expect(datasetNameColCellTexts).to.eql(allDatasetNames); // Search for a dataset await testSubjects.setValue( @@ -83,33 +98,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const datasetNameColAfterSearch = colsAfterSearch['Data Set Name']; const datasetNameColCellTextsAfterSearch = await datasetNameColAfterSearch.getCellTexts(); expect(datasetNameColCellTextsAfterSearch).to.eql([datasetNames[2]]); - await testSubjects.setValue( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFilterBarFieldSearch, - '' - ); + // Reset the search field + await testSubjects.click('clearSearchButton'); }); it('filters for integration', async () => { - const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; - const apacheIntegrationName = 'Apache HTTP Server'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ to, count: 10, dataset: apacheAccessDatasetName }) - ); - - await PageObjects.datasetQuality.navigateTo(); - const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetNameCol = cols['Data Set Name']; const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - expect(datasetNameColCellTexts).to.eql([apacheAccessDatasetHumanName, ...datasetNames]); + expect(datasetNameColCellTexts).to.eql(allDatasetNames); // Filter for integration await PageObjects.datasetQuality.filterForIntegrations([apacheIntegrationName]); @@ -118,64 +115,31 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const datasetNameColAfterFilter = colsAfterFilter['Data Set Name']; const datasetNameColCellTextsAfterFilter = await datasetNameColAfterFilter.getCellTexts(); expect(datasetNameColCellTextsAfterFilter).to.eql([apacheAccessDatasetHumanName]); + // Reset the filter by selecting from the dropdown again + await PageObjects.datasetQuality.filterForIntegrations([apacheIntegrationName]); }); it('filters for namespace', async () => { - const apacheAccessDatasetName = 'apache.access'; - const datasetNamespace = 'prod'; - - await PageObjects.observabilityLogsExplorer.navigateTo(); - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ - to, - count: 10, - dataset: apacheAccessDatasetName, - namespace: datasetNamespace, - }) - ); - - await PageObjects.datasetQuality.navigateTo(); - // Get default namespaces const cols = await PageObjects.datasetQuality.parseDatasetTable(); const namespaceCol = cols.Namespace; const namespaceColCellTexts = await namespaceCol.getCellTexts(); - expect(namespaceColCellTexts).to.contain(defaultNamespace); + expect(namespaceColCellTexts).to.contain(productionNamespace); // Filter for prod namespace - await PageObjects.datasetQuality.filterForNamespaces([datasetNamespace]); + await PageObjects.datasetQuality.filterForNamespaces([productionNamespace]); const colsAfterFilter = await PageObjects.datasetQuality.parseDatasetTable(); const namespaceColAfterFilter = colsAfterFilter.Namespace; const namespaceColCellTextsAfterFilter = await namespaceColAfterFilter.getCellTexts(); - expect(namespaceColCellTextsAfterFilter).to.eql([datasetNamespace]); + expect(namespaceColCellTextsAfterFilter).to.eql([productionNamespace]); + // Reset the namespace by selecting from the dropdown again + await PageObjects.datasetQuality.filterForNamespaces([productionNamespace]); }); it('filters for quality', async () => { - const apacheAccessDatasetName = 'apache.access'; const expectedQuality = 'Poor'; - - // Add initial integrations - await PageObjects.observabilityLogsExplorer.setupInitialIntegrations(); - - // Index 10 logs for `logs-apache.access` dataset - await synthtrace.index( - getLogsForDataset({ - to: new Date().toISOString(), - count: 10, - dataset: apacheAccessDatasetName, - isMalformed: true, - }) - ); - - await PageObjects.datasetQuality.navigateTo(); - // Get default quality const cols = await PageObjects.datasetQuality.parseDatasetTable(); const datasetQuality = cols['Data Set Quality']; @@ -190,6 +154,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const datasetQualityCellTextsAfterFilter = await datasetQualityAfterFilter.getCellTexts(); expect(datasetQualityCellTextsAfterFilter).to.eql([expectedQuality]); + + // Reset the namespace by selecting from the dropdown again + await PageObjects.datasetQuality.filterForQualities([expectedQuality]); }); }); } From a2671433d90113fb5d2f314fab03777919ba7558 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 20 Jun 2024 11:16:17 -0400 Subject: [PATCH 119/123] [Fleet] Fix package upgrade variable merge (#186483) --- .../hooks/use_package_policy.test.tsx | 270 ++++++++++++++++++ .../hooks/use_package_policy.tsx | 11 +- 2 files changed, 272 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.test.tsx index 731a6b9791d7a3..67b8f35a22eb4c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.test.tsx @@ -14,6 +14,7 @@ import { omit } from 'lodash'; +import { sendGetPackageInfoByKey, sendUpgradePackagePolicyDryRun } from '../../../../../../hooks'; import { createFleetTestRendererMock } from '../../../../../../mock'; import { usePackagePolicyWithRelatedData } from './use_package_policy'; @@ -83,6 +84,41 @@ jest.mock('../../../../../../hooks/use_request', () => ({ }, }; } + if (packagePolicyId === 'package-policy-2') { + return { + data: { + item: { + id: 'nginx-1', + name: 'nginx-1', + namespace: 'default', + description: 'Nginx description', + package: { name: 'nginx', title: 'Nginx', version: '1.3.0' }, + enabled: true, + policy_id: 'agent-policy-1', + policy_ids: ['agent-policy-1'], + inputs: [ + { + type: 'logfile', + policy_template: 'nginx', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { type: 'logs', dataset: 'nginx.access' }, + vars: { + paths: { value: ['/var/log/nginx/access.log*'], type: 'text' }, + }, + }, + ], + vars: { + existing_input_level_var: { value: 'existing-value', type: 'text' }, + }, + }, + ], + }, + }, + }; + } }, sendGetPackageInfoByKey: jest.fn().mockImplementation((name, version) => Promise.resolve({ @@ -308,4 +344,238 @@ describe('usePackagePolicy', () => { } `); }); + + it('should load the package policy if this is an upgrade with new input vars', async () => { + jest.mocked(sendUpgradePackagePolicyDryRun).mockResolvedValue({ + data: [ + { + diff: [ + { + id: 'nginx-1', + name: 'nginx-1', + namespace: 'default', + description: 'Nginx description', + package: { name: 'nginx', title: 'Nginx', version: '1.3.0' }, + enabled: true, + policy_id: 'agent-policy-1', + policy_ids: ['agent-policy-1'], + vars: {}, + inputs: [ + { + type: 'logfile', + policy_template: 'nginx', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { type: 'logs', dataset: 'nginx.access' }, + vars: { + paths: { value: ['/var/log/nginx/access.log*'], type: 'text' }, + existing_package_level_var: { + value: '/var/log/nginx/access.log*', + type: 'text', + }, + }, + }, + ], + vars: { + existing_package_level_var: { + value: '/var/log/nginx/access.log*', + type: 'text', + }, + }, + }, + ], + }, + { + id: 'nginx-1', + name: 'nginx-1', + namespace: 'default', + description: 'Nginx description', + package: { name: 'nginx', title: 'Nginx', version: '1.4.0' }, + enabled: true, + policy_id: 'agent-policy-1', + policy_ids: ['agent-policy-1'], + vars: { + new_package_level_var: { value: 'test', type: 'text' }, + }, + inputs: [ + { + type: 'logfile', + policy_template: 'nginx', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { type: 'logs', dataset: 'nginx.access' }, + vars: { + paths: { value: ['/var/log/nginx/access.log*'], type: 'text' }, + }, + }, + ], + vars: { + new_input_level_var: { value: 'test', type: 'text' }, + existing_input_level_var: { + value: 'default_value', + type: 'text', + }, + }, + }, + ], + }, + ], + }, + ], + } as any); + jest.mocked(sendGetPackageInfoByKey).mockResolvedValue({ + data: { + item: { + name: 'nginx', + title: 'Nginx', + version: '1.4.0', + release: 'ga', + description: 'Collect logs and metrics from Nginx HTTP servers with Elastic Agent.', + policy_templates: [ + { + name: 'nginx', + title: 'Nginx logs and metrics', + description: 'Collect logs and metrics from Nginx instances', + inputs: [ + { + type: 'logfile', + title: 'Collect logs from Nginx instances', + description: 'Collecting Nginx access and error logs', + vars: [ + { + name: 'new_input_level_var', + type: 'text', + title: 'Paths', + required: false, + show_user: true, + }, + { + name: 'existing_input_level_var', + type: 'text', + title: 'Paths', + required: false, + show_user: true, + }, + ], + }, + ], + multiple: true, + }, + ], + data_streams: [ + { + type: 'logs', + dataset: 'nginx.access', + title: 'Nginx access logs', + release: 'experimental', + ingest_pipeline: 'default', + streams: [ + { + input: 'logfile', + vars: [ + { + name: 'paths', + type: 'text', + title: 'Paths', + multi: true, + required: true, + show_user: true, + default: ['/var/log/nginx/access.log*'], + }, + ], + template_path: 'stream.yml.hbs', + title: 'Nginx access logs', + description: 'Collect Nginx access logs', + enabled: true, + }, + ], + package: 'nginx', + path: 'access', + }, + ], + latestVersion: '1.4.0', + keepPoliciesUpToDate: false, + status: 'not_installed', + vars: [ + { + name: 'new_package_level_var', + type: 'text', + title: 'Paths', + required: false, + show_user: true, + }, + ], + }, + }, + isLoading: false, + } as any); + const renderer = createFleetTestRendererMock(); + const { result, waitForNextUpdate } = renderer.renderHook(() => + usePackagePolicyWithRelatedData('package-policy-2', { + forceUpgrade: true, + }) + ); + await waitForNextUpdate(); + expect(result.current.packagePolicy).toMatchInlineSnapshot(` + Object { + "description": "Nginx description", + "enabled": true, + "inputs": Array [ + Object { + "enabled": true, + "policy_template": "nginx", + "streams": Array [ + Object { + "data_stream": Object { + "dataset": "nginx.access", + "type": "logs", + }, + "enabled": true, + "vars": Object { + "paths": Object { + "type": "text", + "value": Array [ + "/var/log/nginx/access.log*", + ], + }, + }, + }, + ], + "type": "logfile", + "vars": Object { + "existing_input_level_var": Object { + "type": "text", + "value": "existing-value", + }, + "new_input_level_var": Object { + "type": "text", + "value": "test", + }, + }, + }, + ], + "name": "nginx-1", + "namespace": "default", + "package": Object { + "name": "nginx", + "title": "Nginx", + "version": "1.4.0", + }, + "policy_id": "agent-policy-1", + "policy_ids": Array [ + "agent-policy-1", + ], + "vars": Object { + "new_package_level_var": Object { + "type": "text", + "value": "test", + }, + }, + } + `); + }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx index fe7d70d6976a93..470c6b95e61c01 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx @@ -264,7 +264,7 @@ export function usePackagePolicyWithRelatedData( ...restOfInput } = input; - let basePolicyInputVars: any = + const basePolicyInputVars: any = isUpgradeScenario && basePolicy.inputs.find( (i) => i.type === input.type && i.policy_template === input.policy_template @@ -272,14 +272,7 @@ export function usePackagePolicyWithRelatedData( let newInputVars = inputVars; if (basePolicyInputVars && inputVars) { // merging vars from dry run with updated ones - basePolicyInputVars = Object.keys(inputVars).reduce( - (acc, curr) => ({ ...acc, [curr]: basePolicyInputVars[curr] }), - {} - ); - newInputVars = { - ...inputVars, - ...basePolicyInputVars, - }; + newInputVars = mergeVars(inputVars, basePolicyInputVars); } // Fix duration vars, if it's a migrated setting, and it's a plain old number with no suffix if (basePackage.name === 'apm') { From 8c17c138b997241604d26484166a2497b0f67514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Thu, 20 Jun 2024 17:26:23 +0200 Subject: [PATCH 120/123] fix(serverless/deploy): use `patch` instead of `put` (#186543) ## Summary The `PUT` endpoint was deprecated and removed on [February 20](https://groups.google.com/a/elastic.co/g/dev/c/1S0xcVAbmCA/m/Ybkr1H01AQAJ). We should use `PATCH` when updating the existing projects. --- .buildkite/scripts/steps/serverless/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/scripts/steps/serverless/deploy.sh b/.buildkite/scripts/steps/serverless/deploy.sh index 68c7d285c4c8dd..a439df65aa671d 100644 --- a/.buildkite/scripts/steps/serverless/deploy.sh +++ b/.buildkite/scripts/steps/serverless/deploy.sh @@ -99,7 +99,7 @@ deploy() { -H "Authorization: ApiKey $PROJECT_API_KEY" \ -H "Content-Type: application/json" \ "${PROJECT_API_DOMAIN}/api/v1/serverless/projects/${PROJECT_TYPE}/${PROJECT_ID}" \ - -XPUT -d "$PROJECT_UPDATE_CONFIGURATION" &> $PROJECT_DEPLOY_LOGS + -XPATCH -d "$PROJECT_UPDATE_CONFIGURATION" &> $PROJECT_DEPLOY_LOGS fi echo "Getting project info..." From 7304484cf4f160b92d477f85b59815d8d0c56986 Mon Sep 17 00:00:00 2001 From: Rickyanto Ang Date: Thu, 20 Jun 2024 08:30:19 -0700 Subject: [PATCH 121/123] [Cloud Security] Patch fix for Column label on Cloud Security Data table (#186425) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Screenshot 2024-06-18 at 6 10 05 PM Currently we have an issue where if user already has localStorageKey from previous version where we still use Update for our Column Label and then proceed to upgrading to version where we no longer use that, the column name in Findings table will show field name (it shows resource.id instead of Resource ID) also because we changed the logic and not allow users to change the column headers in the data grid, option to **edit data view field** is removed for Cloud Security Table Screenshot 2024-06-19 at 9 16 06 AM This patch fixes that issues Related to #184295 --- .../cloud_security_data_table.tsx | 45 ++++++++++++------- .../pages/findings.ts | 8 ---- .../pages/vulnerabilities.ts | 8 ---- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx index 623de8401810ce..5c0cbd048f9d12 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx @@ -5,7 +5,12 @@ * 2.0. */ import React, { useState, useMemo } from 'react'; -import { UnifiedDataTableSettings, useColumns } from '@kbn/unified-data-table'; +import _ from 'lodash'; +import { + UnifiedDataTableSettings, + UnifiedDataTableSettingsColumn, + useColumns, +} from '@kbn/unified-data-table'; import { UnifiedDataTable, DataLoadingState } from '@kbn/unified-data-table'; import { CellActionsProvider } from '@kbn/cell-actions'; import { HttpSetup } from '@kbn/core-http-browser'; @@ -130,20 +135,34 @@ export const CloudSecurityDataTable = ({ columnsLocalStorageKey, defaultColumns.map((c) => c.id) ); - const [settings, setSettings] = useLocalStorage( + const [persistedSettings, setPersistedSettings] = useLocalStorage( `${columnsLocalStorageKey}:settings`, { - columns: defaultColumns.reduce((prev, curr) => { - const columnDefaultSettings = curr.width - ? { width: curr.width, display: columnHeaders?.[curr.id] } - : { display: columnHeaders?.[curr.id] }; - const newColumn = { [curr.id]: columnDefaultSettings }; - return { ...prev, ...newColumn }; + columns: defaultColumns.reduce((columnSettings, column) => { + const columnDefaultSettings = column.width ? { width: column.width } : {}; + const newColumn = { [column.id]: columnDefaultSettings }; + return { ...columnSettings, ...newColumn }; }, {} as UnifiedDataTableSettings['columns']), } ); - const { dataView, dataViewIsRefetching, dataViewRefetch } = useDataViewContext(); + const settings = useMemo(() => { + return { + columns: Object.keys(persistedSettings?.columns as UnifiedDataTableSettings).reduce( + (columnSettings, columnId) => { + const newColumn: UnifiedDataTableSettingsColumn = { + ..._.pick(persistedSettings?.columns?.[columnId], ['width']), + display: columnHeaders?.[columnId], + }; + + return { ...columnSettings, [columnId]: newColumn }; + }, + {} as UnifiedDataTableSettings['columns'] + ), + }; + }, [persistedSettings, columnHeaders]); + + const { dataView, dataViewIsRefetching } = useDataViewContext(); const [expandedDoc, setExpandedDoc] = useState(undefined); @@ -161,7 +180,6 @@ export const CloudSecurityDataTable = ({ fieldFormats, toastNotifications, storage, - dataViewFieldEditor, } = useKibana().services; const styles = useStyles(); @@ -176,7 +194,6 @@ export const CloudSecurityDataTable = ({ toastNotifications, storage, data, - dataViewFieldEditor, }; const { @@ -242,14 +259,13 @@ export const CloudSecurityDataTable = ({ ); const onResize = (colSettings: { columnId: string; width: number }) => { - const grid = settings || {}; + const grid = persistedSettings || {}; const newColumns = { ...(grid.columns || {}) }; newColumns[colSettings.columnId] = { width: Math.round(colSettings.width), - display: columnHeaders?.[colSettings.columnId], }; const newGrid = { ...grid, columns: newColumns }; - setSettings(newGrid); + setPersistedSettings(newGrid); }; const externalCustomRenderers = useMemo(() => { @@ -346,7 +362,6 @@ export const CloudSecurityDataTable = ({ gridStyleOverride={gridStyle} rowLineHeightOverride="24px" controlColumnIds={controlColumnIds} - onFieldEdited={dataViewRefetch} /> diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings.ts b/x-pack/test/cloud_security_posture_functional/pages/findings.ts index 6819da2a03e09d..841799dd115f66 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/findings.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/findings.ts @@ -238,14 +238,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('DataTable features', () => { - it('Edit data view field option is Enabled', async () => { - await latestFindingsTable.toggleEditDataViewFieldsOption('result.evaluation'); - expect(await testSubjects.find('gridEditFieldButton')).to.be.ok(); - await latestFindingsTable.toggleEditDataViewFieldsOption('result.evaluation'); - }); - }); - describe('Findings - Fields selector', () => { const CSP_FIELDS_SELECTOR_MODAL = 'cloudSecurityFieldsSelectorModal'; const CSP_FIELDS_SELECTOR_OPEN_BUTTON = 'cloudSecurityFieldsSelectorOpenButton'; diff --git a/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities.ts b/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities.ts index d882d1765f752d..c94fe9b5d046b8 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities.ts @@ -93,14 +93,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('DataTable features', () => { - it('Edit data view field option is Enabled', async () => { - await latestVulnerabilitiesTable.toggleEditDataViewFieldsOption('vulnerability.id'); - expect(await testSubjects.find('gridEditFieldButton')).to.be.ok(); - await latestVulnerabilitiesTable.toggleEditDataViewFieldsOption('vulnerability.id'); - }); - }); - describe('Vulnerabilities - Fields selector', () => { const CSP_FIELDS_SELECTOR_MODAL = 'cloudSecurityFieldsSelectorModal'; const CSP_FIELDS_SELECTOR_OPEN_BUTTON = 'cloudSecurityFieldsSelectorOpenButton'; From 02bc5cff271f9b981ad5d909c4440720b7d29e0b Mon Sep 17 00:00:00 2001 From: Milton Hultgren Date: Thu, 20 Jun 2024 17:39:16 +0200 Subject: [PATCH 122/123] [core-http-router] Add helpers for 201, 207 and 422 status codes (#186379) Closes #186336 by adding helper functions for creating 201, 207 and 422 responses. --- .../src/response.test.ts | 66 ++++++++++++++++--- .../src/response.ts | 5 ++ .../src/router.mock.ts | 3 + .../src/http_server.mocks.ts | 1 + .../src/router/response_factory.ts | 23 +++++++ 5 files changed, 89 insertions(+), 9 deletions(-) diff --git a/packages/core/http/core-http-router-server-internal/src/response.test.ts b/packages/core/http/core-http-router-server-internal/src/response.test.ts index 84f22f076528ca..b80bcbc305c696 100644 --- a/packages/core/http/core-http-router-server-internal/src/response.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/response.test.ts @@ -6,13 +6,61 @@ * Side Public License, v 1. */ -import { fileResponseFactory } from './response'; +import { IKibanaResponse } from '@kbn/core-http-server'; +import { kibanaResponseFactory } from './response'; + +describe('kibanaResponseFactory', () => { + describe('status codes', () => { + const tests: Array<[string, number, IKibanaResponse]> = [ + ['ok', 200, kibanaResponseFactory.ok()], + ['created', 201, kibanaResponseFactory.created()], + ['accepted', 202, kibanaResponseFactory.accepted()], + ['noContent', 204, kibanaResponseFactory.noContent()], + ['multiStatus', 207, kibanaResponseFactory.multiStatus()], + ['redirected', 302, kibanaResponseFactory.redirected({})], + ['notModified', 304, kibanaResponseFactory.notModified({})], + ['badRequest', 400, kibanaResponseFactory.badRequest()], + ['unauthorized', 401, kibanaResponseFactory.unauthorized()], + ['forbidden', 403, kibanaResponseFactory.forbidden()], + ['notFound', 404, kibanaResponseFactory.notFound()], + ['conflict', 409, kibanaResponseFactory.conflict()], + ['unprocessableContent', 422, kibanaResponseFactory.unprocessableContent()], + [ + 'file', + 200, + kibanaResponseFactory.file({ + filename: 'test.txt', + body: 'content', + }), + ], + [ + 'custom:205', + 205, + kibanaResponseFactory.custom({ + statusCode: 205, + }), + ], + [ + 'customError:505', + 505, + kibanaResponseFactory.customError({ + statusCode: 505, + }), + ], + ]; + + it.each(tests)( + '.%s produces a response with status code %i', + (_name, expectedStatusCode, response) => { + expect(response.status).toEqual(expectedStatusCode); + } + ); + }); -describe('fileResponseFactory', () => { describe('res.file', () => { it('returns a kibana response with attachment', () => { const body = Buffer.from('Attachment content'); - const result = fileResponseFactory.file({ + const result = kibanaResponseFactory.file({ body, filename: 'myfile.test', fileContentSize: 30, @@ -31,7 +79,7 @@ describe('fileResponseFactory', () => { it('converts string body content to buffer in response', () => { const body = 'I am a string'; - const result = fileResponseFactory.file({ body, filename: 'myfile.test' }); + const result = kibanaResponseFactory.file({ body, filename: 'myfile.test' }); expect(result.payload?.toString()).toBe(body); }); @@ -39,7 +87,7 @@ describe('fileResponseFactory', () => { const isMultiByte = (str: string) => [...str].some((c) => (c.codePointAt(0) || 0) > 255); const multuByteCharacters = '日本語ダッシュボード.pdf'; - const result = fileResponseFactory.file({ + const result = kibanaResponseFactory.file({ body: 'content', filename: multuByteCharacters, }); @@ -72,7 +120,7 @@ describe('fileResponseFactory', () => { }; const filename = 'myfile.test'; const fileContent = 'content'; - const result = fileResponseFactory.file({ + const result = kibanaResponseFactory.file({ body: fileContent, filename, headers: { ...extraHeaders, ...overrideHeaders }, @@ -88,15 +136,15 @@ describe('fileResponseFactory', () => { describe('content-type', () => { it('default mime type octet-stream', () => { - const result = fileResponseFactory.file({ body: 'content', filename: 'myfile.unknown' }); + const result = kibanaResponseFactory.file({ body: 'content', filename: 'myfile.unknown' }); expect(result.options.headers).toHaveProperty('content-type', 'application/octet-stream'); }); it('gets mime type from filename', () => { - const result = fileResponseFactory.file({ body: 'content', filename: 'myfile.mp4' }); + const result = kibanaResponseFactory.file({ body: 'content', filename: 'myfile.mp4' }); expect(result.options.headers).toHaveProperty('content-type', 'video/mp4'); }); it('gets accepts contentType override', () => { - const result = fileResponseFactory.file({ + const result = kibanaResponseFactory.file({ body: 'content', filename: 'myfile.mp4', fileContentType: 'custom', diff --git a/packages/core/http/core-http-router-server-internal/src/response.ts b/packages/core/http/core-http-router-server-internal/src/response.ts index 14e2bd10c9c14b..b79fd7d812b2bb 100644 --- a/packages/core/http/core-http-router-server-internal/src/response.ts +++ b/packages/core/http/core-http-router-server-internal/src/response.ts @@ -40,8 +40,11 @@ export class KibanaResponse const successResponseFactory: KibanaSuccessResponseFactory = { ok: (options: HttpResponseOptions = {}) => new KibanaResponse(200, options.body, options), + created: (options: HttpResponseOptions = {}) => new KibanaResponse(201, options.body, options), accepted: (options: HttpResponseOptions = {}) => new KibanaResponse(202, options.body, options), noContent: (options: HttpResponseOptions = {}) => new KibanaResponse(204, undefined, options), + multiStatus: (options: HttpResponseOptions = {}) => + new KibanaResponse(207, options.body, options), }; const redirectionResponseFactory: KibanaRedirectionResponseFactory = { @@ -63,6 +66,8 @@ const errorResponseFactory: KibanaErrorResponseFactory = { new KibanaResponse(404, options.body || 'Not Found', options), conflict: (options: ErrorHttpResponseOptions = {}) => new KibanaResponse(409, options.body || 'Conflict', options), + unprocessableContent: (options: ErrorHttpResponseOptions = {}) => + new KibanaResponse(422, options.body || 'Unprocessable Content', options), customError: (options: CustomHttpResponseOptions) => { if (!options || !options.statusCode) { throw new Error( diff --git a/packages/core/http/core-http-router-server-mocks/src/router.mock.ts b/packages/core/http/core-http-router-server-mocks/src/router.mock.ts index d5904699b58131..dfe95000014e7d 100644 --- a/packages/core/http/core-http-router-server-mocks/src/router.mock.ts +++ b/packages/core/http/core-http-router-server-mocks/src/router.mock.ts @@ -119,8 +119,10 @@ function createKibanaRequestMock

({ const createResponseFactoryMock = (): jest.Mocked => ({ ok: jest.fn(), + created: jest.fn(), accepted: jest.fn(), noContent: jest.fn(), + multiStatus: jest.fn(), notModified: jest.fn(), custom: jest.fn(), redirected: jest.fn(), @@ -129,6 +131,7 @@ const createResponseFactoryMock = (): jest.Mocked => ({ forbidden: jest.fn(), notFound: jest.fn(), conflict: jest.fn(), + unprocessableContent: jest.fn(), customError: jest.fn(), file: jest.fn(), }); diff --git a/packages/core/http/core-http-server-mocks/src/http_server.mocks.ts b/packages/core/http/core-http-server-mocks/src/http_server.mocks.ts index 8e7d5543e35eb5..0854e43ebbee45 100644 --- a/packages/core/http/core-http-server-mocks/src/http_server.mocks.ts +++ b/packages/core/http/core-http-server-mocks/src/http_server.mocks.ts @@ -22,6 +22,7 @@ const createLifecycleResponseFactoryMock = (): jest.Mocked ): IKibanaResponse; + /** + * The request has succeeded and has led to the creation of a resource. + * Status code: `201`. + * @param options - {@link HttpResponseOptions} configures HTTP response body & headers. + */ + created( + options?: HttpResponseOptions + ): IKibanaResponse; + /** * The request has been accepted for processing. * Status code: `202`. @@ -46,6 +55,13 @@ export interface KibanaSuccessResponseFactory { * @param options - {@link HttpResponseOptions} configures HTTP response body & headers. */ noContent(options?: HttpResponseOptions): IKibanaResponse; + + /** + * The server indicates that there might be a mixture of responses (some tasks succeeded, some failed). + * Status code: `207`. + * @param options - {@link HttpResponseOptions} configures HTTP response body & headers. + */ + multiStatus(options?: HttpResponseOptions): IKibanaResponse; } /** @@ -112,6 +128,13 @@ export interface KibanaErrorResponseFactory { */ conflict(options?: ErrorHttpResponseOptions): IKibanaResponse; + /** + * The server understands the content type of the request entity, and the syntax of the request entity is correct, but it was unable to process the contained instructions. + * Status code: `422`. + * @param options - {@link HttpResponseOptions} configures HTTP response headers, error message and other error details to pass to the client + */ + unprocessableContent(options?: ErrorHttpResponseOptions): IKibanaResponse; + /** * Creates an error response with defined status code and payload. * @param options - {@link CustomHttpResponseOptions} configures HTTP response headers, error message and other error details to pass to the client From 592aafcaba2298a709582b4dcad10bbf6d61a759 Mon Sep 17 00:00:00 2001 From: Rickyanto Ang Date: Thu, 20 Jun 2024 08:44:56 -0700 Subject: [PATCH 123/123] [Cloud Security][Serverless] Serverless API FTR Test Update on Roles (#186488) ## Summary We no longer uses with Operator role when doing serverless FTR, --- .../apis/cloud_security_posture/helper.ts | 100 +++++++++++----- .../cloud_security_posture/benchmark/v1.ts | 89 ++++++++------ .../cloud_security_posture/benchmark/v2.ts | 71 +++++++---- .../find_csp_benchmark_rule.ts | 110 +++++++++++------- .../status/status_indexed.ts | 65 +++++++---- .../status/status_indexing.ts | 65 +++++++---- .../status_not_deployed_not_installed.ts | 65 +++++++---- .../cloud_security_posture/telemetry.ts | 73 +++++++----- 8 files changed, 417 insertions(+), 221 deletions(-) diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts b/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts index 37bdd4975b2a6c..00bcffd553af11 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts @@ -13,6 +13,12 @@ import type { IndexDetails } from '@kbn/cloud-security-posture-plugin/common/typ import { CLOUD_SECURITY_PLUGIN_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; import { SecurityService } from '../../../../../test/common/services/security/security'; +export interface RoleCredentials { + apiKey: { id: string; name: string }; + apiKeyHeader: { Authorization: string }; + cookieHeader: { Cookie: string }; +} + export const deleteIndex = (es: Client, indexToBeDeleted: string[]) => { Promise.all([ ...indexToBeDeleted.map((indexes) => @@ -50,7 +56,9 @@ export async function createPackagePolicy( input: string, deployment: string, posture: string, - packageName: string = 'cloud_security_posture-1' + packageName: string = 'cloud_security_posture-1', + roleAuthc?: RoleCredentials, + internalRequestHeader?: { 'x-elastic-internal-origin': string; 'kbn-xsrf': string } ) { const version = CLOUD_SECURITY_PLUGIN_VERSION; const title = 'Security Posture Management'; @@ -72,35 +80,67 @@ export async function createPackagePolicy( const inputs = posture === 'vuln_mgmt' ? { ...inputTemplate, streams } : { ...inputTemplate }; - const { body: postPackageResponse } = await supertest - .post(`/api/fleet/package_policies`) - .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') - .set('kbn-xsrf', 'xxxx') - .send({ - force: true, - name: packageName, - description: '', - namespace: 'default', - policy_id: agentPolicyId, - enabled: true, - inputs: [inputs], - package: { - name: 'cloud_security_posture', - title, - version, - }, - vars: { - deployment: { - value: deployment, - type: 'text', - }, - posture: { - value: posture, - type: 'text', - }, - }, - }) - .expect(200); + const { body: postPackageResponse } = + roleAuthc && internalRequestHeader + ? await supertest + .post(`/api/fleet/package_policies`) + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) + .send({ + force: true, + name: packageName, + description: '', + namespace: 'default', + policy_id: agentPolicyId, + enabled: true, + inputs: [inputs], + package: { + name: 'cloud_security_posture', + title, + version, + }, + vars: { + deployment: { + value: deployment, + type: 'text', + }, + posture: { + value: posture, + type: 'text', + }, + }, + }) + .expect(200) + : await supertest + .post(`/api/fleet/package_policies`) + .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') + .set('kbn-xsrf', 'xxxx') + .send({ + force: true, + name: packageName, + description: '', + namespace: 'default', + policy_id: agentPolicyId, + enabled: true, + inputs: [inputs], + package: { + name: 'cloud_security_posture', + title, + version, + }, + vars: { + deployment: { + value: deployment, + type: 'text', + }, + posture: { + value: posture, + type: 'text', + }, + }, + }) + .expect(200); return postPackageResponse.item; } diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/benchmark/v1.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/benchmark/v1.ts index 129b59880312b8..5b4154db95151e 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/benchmark/v1.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/benchmark/v1.ts @@ -6,17 +6,17 @@ */ import expect from '@kbn/expect'; import type { GetBenchmarkResponse } from '@kbn/cloud-security-posture-plugin/common/types/latest'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { FtrProviderContext } from '../../../../ftr_provider_context'; import { createPackagePolicy } from '../../../../../../test/api_integration/apis/cloud_security_posture/helper'; // eslint-disable-line @kbn/imports/no_boundary_crossing +import { RoleCredentials } from '../../../../../shared/services'; export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); describe('GET /internal/cloud_security_posture/benchmark', function () { // security_exception: action [indices:admin/create] is unauthorized for user [elastic] with effective roles [superuser] on restricted indices [.fleet-actions-7], this action is granted by the index privileges [create_index,manage,all] @@ -26,14 +26,26 @@ export default function ({ getService }: FtrProviderContext) { let agentPolicyId2: string; let agentPolicyId3: string; let agentPolicyId4: string; + let roleAuthc: RoleCredentials; + let internalRequestHeader: { 'x-elastic-internal-origin': string; 'kbn-xsrf': string }; + + before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + internalRequestHeader = svlCommonApi.getInternalRequestHeader(); + }); + + after(async () => { + await svlUserManager.invalidateApiKeyForRole(roleAuthc); + }); beforeEach(async () => { await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - const { body: agentPolicyResponse } = await supertest + const { body: agentPolicyResponse } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy', namespace: 'default', @@ -41,9 +53,10 @@ export default function ({ getService }: FtrProviderContext) { agentPolicyId = agentPolicyResponse.item.id; - const { body: agentPolicyResponse2 } = await supertest + const { body: agentPolicyResponse2 } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy 2', namespace: 'default', @@ -51,9 +64,10 @@ export default function ({ getService }: FtrProviderContext) { agentPolicyId2 = agentPolicyResponse2.item.id; - const { body: agentPolicyResponse3 } = await supertest + const { body: agentPolicyResponse3 } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy 3', namespace: 'default', @@ -61,9 +75,10 @@ export default function ({ getService }: FtrProviderContext) { agentPolicyId3 = agentPolicyResponse3.item.id; - const { body: agentPolicyResponse4 } = await supertest + const { body: agentPolicyResponse4 } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy 4', namespace: 'default', @@ -72,43 +87,51 @@ export default function ({ getService }: FtrProviderContext) { agentPolicyId4 = agentPolicyResponse4.item.id; await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'cspm', 'cloudbeat/cis_aws', 'aws', 'cspm', - 'CSPM-1' + 'CSPM-1', + roleAuthc, + internalRequestHeader ); await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId2, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', 'kspm', - 'KSPM-1' + 'KSPM-1', + roleAuthc, + internalRequestHeader ); await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId3, 'vuln_mgmt', 'cloudbeat/vuln_mgmt_aws', 'aws', 'vuln_mgmt', - 'CNVM-1' + 'CNVM-1', + roleAuthc, + internalRequestHeader ); await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId4, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', 'kspm', - 'KSPM-2' + 'KSPM-2', + roleAuthc, + internalRequestHeader ); }); @@ -118,44 +141,44 @@ export default function ({ getService }: FtrProviderContext) { }); it(`Should return non-empty array filled with Rules if user has CSP integrations`, async () => { - const { body: res }: { body: GetBenchmarkResponse } = await supertest + const { body: res }: { body: GetBenchmarkResponse } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/benchmarks`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.items.length).equal(3); }); it(`Should return array size 2 when we set per page to be only 2 (total element is still 3)`, async () => { - const { body: res }: { body: GetBenchmarkResponse } = await supertest + const { body: res }: { body: GetBenchmarkResponse } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/benchmarks?per_page=2`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.items.length).equal(2); }); it(`Should return array size 2 when we set per page to be only 2 (total element is still 3)`, async () => { - const { body: res }: { body: GetBenchmarkResponse } = await supertest + const { body: res }: { body: GetBenchmarkResponse } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/benchmarks?per_page=2&page=2`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.items.length).equal(1); }); it(`Should return empty array when we set page to be above the last page number`, async () => { - const { body: res }: { body: GetBenchmarkResponse } = await supertest + const { body: res }: { body: GetBenchmarkResponse } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/benchmarks?per_page=2&page=3`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.items.length).equal(0); diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/benchmark/v2.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/benchmark/v2.ts index a6e856ea0129eb..9eff835396680f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/benchmark/v2.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/benchmark/v2.ts @@ -6,17 +6,17 @@ */ import expect from '@kbn/expect'; import type { GetBenchmarkResponse } from '@kbn/cloud-security-posture-plugin/common/types/latest'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { FtrProviderContext } from '../../../../ftr_provider_context'; import { createPackagePolicy } from '../../../../../../test/api_integration/apis/cloud_security_posture/helper'; // eslint-disable-line @kbn/imports/no_boundary_crossing +import { RoleCredentials } from '../../../../../shared/services'; export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('GET /internal/cloud_security_posture/benchmark', function () { // security_exception: action [indices:admin/create] is unauthorized for user [elastic] with effective roles [superuser] on restricted indices [.fleet-actions-7], this action is granted by the index privileges [create_index,manage,all] @@ -26,14 +26,26 @@ export default function ({ getService }: FtrProviderContext) { let agentPolicyId2: string; let agentPolicyId3: string; let agentPolicyId4: string; + let roleAuthc: RoleCredentials; + let internalRequestHeader: { 'x-elastic-internal-origin': string; 'kbn-xsrf': string }; + + before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + internalRequestHeader = svlCommonApi.getInternalRequestHeader(); + }); + + after(async () => { + await svlUserManager.invalidateApiKeyForRole(roleAuthc); + }); beforeEach(async () => { await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - const { body: agentPolicyResponse } = await supertest + const { body: agentPolicyResponse } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy', namespace: 'default', @@ -41,9 +53,10 @@ export default function ({ getService }: FtrProviderContext) { agentPolicyId = agentPolicyResponse.item.id; - const { body: agentPolicyResponse2 } = await supertest + const { body: agentPolicyResponse2 } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy 2', namespace: 'default', @@ -51,9 +64,10 @@ export default function ({ getService }: FtrProviderContext) { agentPolicyId2 = agentPolicyResponse2.item.id; - const { body: agentPolicyResponse3 } = await supertest + const { body: agentPolicyResponse3 } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy 3', namespace: 'default', @@ -61,9 +75,10 @@ export default function ({ getService }: FtrProviderContext) { agentPolicyId3 = agentPolicyResponse3.item.id; - const { body: agentPolicyResponse4 } = await supertest + const { body: agentPolicyResponse4 } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy 4', namespace: 'default', @@ -72,43 +87,51 @@ export default function ({ getService }: FtrProviderContext) { agentPolicyId4 = agentPolicyResponse4.item.id; await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'cspm', 'cloudbeat/cis_aws', 'aws', 'cspm', - 'CSPM-1' + 'CSPM-1', + roleAuthc, + internalRequestHeader ); await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId2, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', 'kspm', - 'KSPM-1' + 'KSPM-1', + roleAuthc, + internalRequestHeader ); await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId3, 'vuln_mgmt', 'cloudbeat/vuln_mgmt_aws', 'aws', 'vuln_mgmt', - 'CNVM-1' + 'CNVM-1', + roleAuthc, + internalRequestHeader ); await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId4, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', 'kspm', - 'KSPM-2' + 'KSPM-2', + roleAuthc, + internalRequestHeader ); }); @@ -118,11 +141,11 @@ export default function ({ getService }: FtrProviderContext) { }); it(`Should return all benchmarks if user has CSP integrations`, async () => { - const { body: res }: { body: GetBenchmarkResponse } = await supertest + const { body: res }: { body: GetBenchmarkResponse } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/benchmarks`) .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.items.length).equal(5); diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/find_csp_benchmark_rule.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/find_csp_benchmark_rule.ts index 8209e9965a9a27..91c2e950877b1c 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/find_csp_benchmark_rule.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/find_csp_benchmark_rule.ts @@ -5,10 +5,7 @@ * 2.0. */ import expect from '@kbn/expect'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import type { CspBenchmarkRule, FindCspBenchmarkRuleResponse, @@ -16,11 +13,14 @@ import type { import { FtrProviderContext } from '../../../ftr_provider_context'; import { createPackagePolicy } from '../../../../../test/api_integration/apis/cloud_security_posture/helper'; // eslint-disable-line @kbn/imports/no_boundary_crossing +import { RoleCredentials } from '../../../../shared/services'; export default function ({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); // find csp benchmark rule tests describe('GET internal/cloud_security_posture/rules/_find', function () { @@ -28,14 +28,26 @@ export default function ({ getService }: FtrProviderContext) { this.tags(['failsOnMKI']); let agentPolicyId: string; + let roleAuthc: RoleCredentials; + let internalRequestHeader: { 'x-elastic-internal-origin': string; 'kbn-xsrf': string }; + + before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + internalRequestHeader = svlCommonApi.getInternalRequestHeader(); + }); + + after(async () => { + await svlUserManager.invalidateApiKeyForRole(roleAuthc); + }); beforeEach(async () => { await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - const { body: agentPolicyResponse } = await supertest + const { body: agentPolicyResponse } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy', namespace: 'default', @@ -51,19 +63,22 @@ export default function ({ getService }: FtrProviderContext) { it(`Should return 500 error code when not provide package policy id or benchmark id`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', - 'kspm' + 'kspm', + 'KSPM-1', + roleAuthc, + internalRequestHeader ); - const { body }: { body: { message: string } } = await supertest + const { body }: { body: { message: string } } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/rules/_find`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(500); expect(body.message).to.eql( @@ -74,19 +89,22 @@ export default function ({ getService }: FtrProviderContext) { it(`Should return 500 error code when provide both package policy id and benchmark id`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', - 'kspm' + 'kspm', + 'KSPM-2', + roleAuthc, + internalRequestHeader ); - const { body }: { body: { message: string } } = await supertest + const { body }: { body: { message: string } } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/rules/_find`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .query({ packagePolicyId: 'your-package-policy-id', benchmarkId: 'cis_aws', @@ -100,11 +118,11 @@ export default function ({ getService }: FtrProviderContext) { }); it(`Should return 404 status code when the package policy ID does not exist`, async () => { - const { body }: { body: { statusCode: number; error: string } } = await supertest + const { body }: { body: { statusCode: number; error: string } } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/rules/_find`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .query({ packagePolicyId: 'non-existing-packagePolicy-id', }) @@ -122,19 +140,22 @@ export default function ({ getService }: FtrProviderContext) { it(`Should return 200 status code and filter rules by benchmarkId`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', - 'kspm' + 'kspm', + 'KSPM-3', + roleAuthc, + internalRequestHeader ); - const { body }: { body: FindCspBenchmarkRuleResponse } = await supertest + const { body }: { body: FindCspBenchmarkRuleResponse } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/rules/_find`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .query({ benchmarkId: 'cis_k8s', }) @@ -154,19 +175,22 @@ export default function ({ getService }: FtrProviderContext) { it(`Should return 200 status code, and only requested fields in the response`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', - 'kspm' + 'kspm', + 'KSPM-4', + roleAuthc, + internalRequestHeader ); - const { body }: { body: FindCspBenchmarkRuleResponse } = await supertest + const { body }: { body: FindCspBenchmarkRuleResponse } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/rules/_find`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .query({ benchmarkId: 'cis_k8s', fields: ['metadata.name', 'metadata.section', 'metadata.id'], @@ -188,19 +212,22 @@ export default function ({ getService }: FtrProviderContext) { it(`Should return 200 status code, items sorted by metadata.section field`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', - 'kspm' + 'kspm', + 'KSPM-5', + roleAuthc, + internalRequestHeader ); - const { body }: { body: FindCspBenchmarkRuleResponse } = await supertest + const { body }: { body: FindCspBenchmarkRuleResponse } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/rules/_find`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .query({ benchmarkId: 'cis_k8s', sortField: 'metadata.section', @@ -223,19 +250,22 @@ export default function ({ getService }: FtrProviderContext) { const perPage = 10; await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', - 'kspm' + 'kspm', + 'KSPM-6', + roleAuthc, + internalRequestHeader ); - const { body }: { body: FindCspBenchmarkRuleResponse } = await supertest + const { body }: { body: FindCspBenchmarkRuleResponse } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/rules/_find`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set('kbn-xsrf', 'xxxx') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .query({ benchmarkId: 'cis_k8s', perPage, diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts index ec3216971ec35c..b03368fbdaeb9b 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts @@ -5,10 +5,7 @@ * 2.0. */ import expect from '@kbn/expect'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; import { FINDINGS_INDEX_DEFAULT_NS, @@ -26,6 +23,7 @@ import { findingsMockData, vulnerabilityMockData, } from '../../../../../../test/api_integration/apis/cloud_security_posture/mock_data'; // eslint-disable-line @kbn/imports/no_boundary_crossing +import { RoleCredentials } from '../../../../../shared/services'; const INDEX_ARRAY = [ FINDINGS_INDEX_DEFAULT_NS, @@ -36,25 +34,39 @@ const INDEX_ARRAY = [ export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; - const supertest = getService('supertest'); const es = getService('es'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); describe('GET /internal/cloud_security_posture/status', function () { // security_exception: action [indices:admin/create] is unauthorized for user [elastic] with effective roles [superuser] on restricted indices [.fleet-actions-7], this action is granted by the index privileges [create_index,manage,all] this.tags(['failsOnMKI']); let agentPolicyId: string; + let roleAuthc: RoleCredentials; + let internalRequestHeader: { 'x-elastic-internal-origin': string; 'kbn-xsrf': string }; + + before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + internalRequestHeader = svlCommonApi.getInternalRequestHeader(); + }); + + after(async () => { + await svlUserManager.invalidateApiKeyForRole(roleAuthc); + }); describe('STATUS = INDEXED TEST', () => { beforeEach(async () => { await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - const { body: agentPolicyResponse } = await supertest + const { body: agentPolicyResponse } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy', namespace: 'default', @@ -75,19 +87,22 @@ export default function (providerContext: FtrProviderContext) { it(`Return kspm status indexed when logs-cloud_security_posture.findings_latest-default contains new kspm documents`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', - 'kspm' + 'kspm', + 'KSPM-1', + roleAuthc, + internalRequestHeader ); - const { body: res }: { body: CspSetupStatus } = await supertest + const { body: res }: { body: CspSetupStatus } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.kspm.status).to.eql( @@ -98,19 +113,22 @@ export default function (providerContext: FtrProviderContext) { it(`Return cspm status indexed when logs-cloud_security_posture.findings_latest-default contains new cspm documents`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'cspm', 'cloudbeat/cis_aws', 'aws', - 'cspm' + 'cspm', + 'CSPM-1', + roleAuthc, + internalRequestHeader ); - const { body: res }: { body: CspSetupStatus } = await supertest + const { body: res }: { body: CspSetupStatus } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.cspm.status).to.eql( @@ -121,19 +139,22 @@ export default function (providerContext: FtrProviderContext) { it(`Return vuln status indexed when logs-cloud_security_posture.vulnerabilities_latest-default contains new documents`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'vuln_mgmt', 'cloudbeat/vuln_mgmt_aws', 'aws', - 'vuln_mgmt' + 'vuln_mgmt', + 'CNVM-1', + roleAuthc, + internalRequestHeader ); - const { body: res }: { body: CspSetupStatus } = await supertest + const { body: res }: { body: CspSetupStatus } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.vuln_mgmt.status).to.eql( diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts index 17e1e6458edaa6..559e9e7b43c999 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts @@ -5,10 +5,7 @@ * 2.0. */ import expect from '@kbn/expect'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; import { FINDINGS_INDEX_DEFAULT_NS, @@ -26,6 +23,7 @@ import { findingsMockData, vulnerabilityMockData, } from '../../../../../../test/api_integration/apis/cloud_security_posture/mock_data'; // eslint-disable-line @kbn/imports/no_boundary_crossing +import { RoleCredentials } from '../../../../../shared/services'; const INDEX_ARRAY = [ FINDINGS_INDEX_DEFAULT_NS, @@ -36,25 +34,39 @@ const INDEX_ARRAY = [ export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; - const supertest = getService('supertest'); const es = getService('es'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); describe('GET /internal/cloud_security_posture/status', function () { // security_exception: action [indices:admin/create] is unauthorized for user [elastic] with effective roles [superuser] on restricted indices [.fleet-actions-7], this action is granted by the index privileges [create_index,manage,all] this.tags(['failsOnMKI']); let agentPolicyId: string; + let roleAuthc: RoleCredentials; + let internalRequestHeader: { 'x-elastic-internal-origin': string; 'kbn-xsrf': string }; + + before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + internalRequestHeader = svlCommonApi.getInternalRequestHeader(); + }); + + after(async () => { + await svlUserManager.invalidateApiKeyForRole(roleAuthc); + }); describe('STATUS = INDEXING TEST', () => { beforeEach(async () => { await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - const { body: agentPolicyResponse } = await supertest + const { body: agentPolicyResponse } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy', namespace: 'default', @@ -74,19 +86,22 @@ export default function (providerContext: FtrProviderContext) { it(`Return kspm status indexing when logs-cloud_security_posture.findings_latest-default doesn't contain new kspm documents, but has newly connected agents`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', - 'kspm' + 'kspm', + 'KSPM-1', + roleAuthc, + internalRequestHeader ); - const { body: res }: { body: CspSetupStatus } = await supertest + const { body: res }: { body: CspSetupStatus } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.kspm.status).to.eql( @@ -97,19 +112,22 @@ export default function (providerContext: FtrProviderContext) { it(`Return cspm status indexing when logs-cloud_security_posture.findings_latest-default doesn't contain new cspm documents, but has newly connected agents `, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'cspm', 'cloudbeat/cis_aws', 'aws', - 'cspm' + 'cspm', + 'CSPM-1', + roleAuthc, + internalRequestHeader ); - const { body: res }: { body: CspSetupStatus } = await supertest + const { body: res }: { body: CspSetupStatus } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.cspm.status).to.eql( @@ -120,19 +138,22 @@ export default function (providerContext: FtrProviderContext) { it(`Return vuln status indexing when logs-cloud_security_posture.vulnerabilities_latest-default doesn't contain vuln new documents, but has newly connected agents`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'vuln_mgmt', 'cloudbeat/vuln_mgmt_aws', 'aws', - 'vuln_mgmt' + 'vuln_mgmt', + 'CNVM-1', + roleAuthc, + internalRequestHeader ); - const { body: res }: { body: CspSetupStatus } = await supertest + const { body: res }: { body: CspSetupStatus } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.vuln_mgmt.status).to.eql( diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_not_deployed_not_installed.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_not_deployed_not_installed.ts index 9dc25ca4a1133f..1cf6e453ea1f39 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_not_deployed_not_installed.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_not_deployed_not_installed.ts @@ -6,33 +6,45 @@ */ import expect from '@kbn/expect'; import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { FtrProviderContext } from '../../../../ftr_provider_context'; import { createPackagePolicy } from '../../../../../../test/api_integration/apis/cloud_security_posture/helper'; // eslint-disable-line @kbn/imports/no_boundary_crossing +import { RoleCredentials } from '../../../../../shared/services'; export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; - const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); describe('GET /internal/cloud_security_posture/status', function () { // security_exception: action [indices:admin/create] is unauthorized for user [elastic] with effective roles [superuser] on restricted indices [.fleet-actions-7], this action is granted by the index privileges [create_index,manage,all] this.tags(['failsOnMKI']); let agentPolicyId: string; + let roleAuthc: RoleCredentials; + let internalRequestHeader: { 'x-elastic-internal-origin': string; 'kbn-xsrf': string }; + + before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + internalRequestHeader = svlCommonApi.getInternalRequestHeader(); + }); + + after(async () => { + await svlUserManager.invalidateApiKeyForRole(roleAuthc); + }); describe('STATUS = NOT-DEPLOYED and STATUS = NOT-INSTALLED TEST', () => { beforeEach(async () => { await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - const { body: agentPolicyResponse } = await supertest + const { body: agentPolicyResponse } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy', namespace: 'default', @@ -47,19 +59,22 @@ export default function (providerContext: FtrProviderContext) { }); it(`Should return not-deployed when installed kspm, no findings on either indices and no healthy agents`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'kspm', 'cloudbeat/cis_k8s', 'vanilla', - 'kspm' + 'kspm', + 'KSPM-1', + roleAuthc, + internalRequestHeader ); - const { body: res }: { body: CspSetupStatus } = await supertest + const { body: res }: { body: CspSetupStatus } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.kspm.status).to.eql( @@ -86,19 +101,22 @@ export default function (providerContext: FtrProviderContext) { it(`Should return not-deployed when installed cspm, no findings on either indices and no healthy agents`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'cspm', 'cloudbeat/cis_aws', 'aws', - 'cspm' + 'cspm', + 'CSPM-1', + roleAuthc, + internalRequestHeader ); - const { body: res }: { body: CspSetupStatus } = await supertest + const { body: res }: { body: CspSetupStatus } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.cspm.status).to.eql( @@ -125,19 +143,22 @@ export default function (providerContext: FtrProviderContext) { it(`Should return not-deployed when installed cnvm, no findings on either indices and no healthy agents`, async () => { await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'vuln_mgmt', 'cloudbeat/vuln_mgmt_aws', 'aws', - 'vuln_mgmt' + 'vuln_mgmt', + 'CNVM-1', + roleAuthc, + internalRequestHeader ); - const { body: res }: { body: CspSetupStatus } = await supertest + const { body: res }: { body: CspSetupStatus } = await supertestWithoutAuth .get(`/internal/cloud_security_posture/status`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .expect(200); expect(res.cspm.status).to.eql( diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/telemetry.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/telemetry.ts index 155d85dc0f06c4..b4f82203ecdf78 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/telemetry.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/telemetry.ts @@ -6,37 +6,48 @@ */ import expect from '@kbn/expect'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; +import type { Agent as SuperTestAgent } from 'supertest'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import type { FtrProviderContext } from '../../../ftr_provider_context'; import { data as telemetryMockData, MockTelemetryFindings, } from '../../../../../test/cloud_security_posture_api/telemetry/data'; // eslint-disable-line @kbn/imports/no_boundary_crossing import { createPackagePolicy } from '../../../../../test/api_integration/apis/cloud_security_posture/helper'; // eslint-disable-line @kbn/imports/no_boundary_crossing +import { RoleCredentials } from '../../../../shared/services'; const FINDINGS_INDEX = 'logs-cloud_security_posture.findings_latest-default'; export default function ({ getService }: FtrProviderContext) { const retry = getService('retry'); const es = getService('es'); - const supertest = getService('supertest'); const log = getService('log'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); + + let roleAuthc: RoleCredentials; + let internalRequestHeader: { 'x-elastic-internal-origin': string; 'kbn-xsrf': string }; /** * required before indexing findings */ - const waitForPluginInitialized = (): Promise => + const waitForPluginInitialized = ( + supertestWithoutAuthParam: SuperTestAgent, + internalRequestHeaderParam: { 'x-elastic-internal-origin': string; 'kbn-xsrf': string }, + roleAuthcParam: RoleCredentials + ): Promise => retry.try(async () => { log.debug('Check CSP plugin is initialized'); - const response = await supertest + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + internalRequestHeader = svlCommonApi.getInternalRequestHeader(); + const response = await supertestWithoutAuthParam .get('/internal/cloud_security_posture/status?check=init') .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'xxx') + .set(internalRequestHeaderParam) + .set(roleAuthcParam.apiKeyHeader) .expect(200); expect(response.body).to.eql({ isPluginInitialized: true }); log.debug('CSP plugin is initialized'); @@ -68,12 +79,15 @@ export default function ({ getService }: FtrProviderContext) { let agentPolicyId: string; before(async () => { + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + internalRequestHeader = svlCommonApi.getInternalRequestHeader(); await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - const { body: agentPolicyResponse } = await supertest + const { body: agentPolicyResponse } = await supertestWithoutAuth .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ name: 'Test policy', namespace: 'default', @@ -82,18 +96,21 @@ export default function ({ getService }: FtrProviderContext) { agentPolicyId = agentPolicyResponse.item.id; await createPackagePolicy( - supertest, + supertestWithoutAuth, agentPolicyId, 'cspm', 'cloudbeat/cis_aws', 'aws', 'cspm', - 'CSPM-1' + 'CSPM-1', + roleAuthc, + internalRequestHeader ); - await waitForPluginInitialized(); + await waitForPluginInitialized(supertestWithoutAuth, internalRequestHeader, roleAuthc); }); after(async () => { + await svlUserManager.invalidateApiKeyForRole(roleAuthc); await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); }); @@ -107,11 +124,11 @@ export default function ({ getService }: FtrProviderContext) { const { body: [{ stats: apiResponse }], - } = await supertest + } = await supertestWithoutAuth .post(`/internal/telemetry/clusters/_stats`) .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .set('kbn-xsrf', 'xxxx') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ unencrypted: true, refreshCache: true, @@ -161,11 +178,11 @@ export default function ({ getService }: FtrProviderContext) { const { body: [{ stats: apiResponse }], - } = await supertest + } = await supertestWithoutAuth .post(`/internal/telemetry/clusters/_stats`) - .set('kbn-xsrf', 'xxxx') .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ unencrypted: true, refreshCache: true, @@ -208,11 +225,11 @@ export default function ({ getService }: FtrProviderContext) { const { body: [{ stats: apiResponse }], - } = await supertest + } = await supertestWithoutAuth .post(`/internal/telemetry/clusters/_stats`) - .set('kbn-xsrf', 'xxxx') .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ unencrypted: true, refreshCache: true, @@ -286,11 +303,11 @@ export default function ({ getService }: FtrProviderContext) { const { body: [{ stats: apiResponse }], - } = await supertest + } = await supertestWithoutAuth .post(`/internal/telemetry/clusters/_stats`) - .set('kbn-xsrf', 'xxxx') .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ unencrypted: true, refreshCache: true, @@ -342,11 +359,11 @@ export default function ({ getService }: FtrProviderContext) { const { body: [{ stats: apiResponse }], - } = await supertest + } = await supertestWithoutAuth .post(`/internal/telemetry/clusters/_stats`) - .set('kbn-xsrf', 'xxxx') .set(ELASTIC_HTTP_VERSION_HEADER, '2') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set(internalRequestHeader) + .set(roleAuthc.apiKeyHeader) .send({ unencrypted: true, refreshCache: true,